mirror of
https://github.com/haproxy/haproxy.git
synced 2026-03-29 13:54:26 -04:00
Compare commits
305 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fd5cafe27 | ||
|
|
d26bd9f978 | ||
|
|
506cfcb5d4 | ||
|
|
418f0c0bbe | ||
|
|
27d7c69e87 | ||
|
|
d1c7e56585 | ||
|
|
4e99cddde4 | ||
|
|
0e36267aac | ||
|
|
1b0dfff552 | ||
|
|
d3ad730d5f | ||
|
|
cca9245416 | ||
|
|
07edaed191 | ||
|
|
1c1d9d2500 | ||
|
|
47987ccbd9 | ||
|
|
33041fe91f | ||
|
|
8e250bba8f | ||
|
|
c7564c19a2 | ||
|
|
efbf0f8ed1 | ||
|
|
52d8ee85e7 | ||
|
|
38a7d8599d | ||
|
|
82afd36b6c | ||
|
|
ada33006ef | ||
|
|
163eba5c8c | ||
|
|
61d68f14b2 | ||
|
|
125cbecfa9 | ||
|
|
a61ea0f414 | ||
|
|
cd363e0246 | ||
|
|
d257dd4563 | ||
|
|
39121ceca6 | ||
|
|
c9a9fa813b | ||
|
|
181cd8ba8a | ||
|
|
5acdda4eed | ||
|
|
92a24a4e87 | ||
|
|
467f911cea | ||
|
|
0213dd70c9 | ||
|
|
5ead611cc2 | ||
|
|
41c89e4fb6 | ||
|
|
b71f70d548 | ||
|
|
01b9b67d5c | ||
|
|
f8c96bf9cb | ||
|
|
4d6cba03f2 | ||
|
|
1c379cad88 | ||
|
|
3d9865a12c | ||
|
|
d72be950bd | ||
|
|
5a0fbbf1ca | ||
|
|
c6fc53aa99 | ||
|
|
2ca7601c2d | ||
|
|
d250b381dc | ||
|
|
5b184e4178 | ||
|
|
fedaf054c4 | ||
|
|
8e469ebf2e | ||
|
|
ff7b06badb | ||
|
|
5d0f5f8168 | ||
|
|
ed6a4bc807 | ||
|
|
282b9b7d16 | ||
|
|
6982c2539f | ||
|
|
9852d5be26 | ||
|
|
7d40b3134a | ||
|
|
8f6cb8f452 | ||
|
|
60c9e2975b | ||
|
|
5617e47f91 | ||
|
|
042b7ab763 | ||
|
|
7466f64c56 | ||
|
|
15b005fd1e | ||
|
|
f1e8173a43 | ||
|
|
4c61e9028c | ||
|
|
932d77e287 | ||
|
|
c238965b27 | ||
|
|
b63492e4f4 | ||
|
|
b3a84800b4 | ||
|
|
eec60f14dd | ||
|
|
fc38ebb079 | ||
|
|
10e78d9246 | ||
|
|
4e937e0391 | ||
|
|
05a295441c | ||
|
|
4e57516c9a | ||
|
|
e31640368a | ||
|
|
0e231bbd7c | ||
|
|
1696cfaa19 | ||
|
|
c6221db375 | ||
|
|
b93137ce67 | ||
|
|
e07c9ee575 | ||
|
|
de4f7eaeed | ||
|
|
e1738b665d | ||
|
|
6152a4eef5 | ||
|
|
94a4578ccf | ||
|
|
c1dfea3ab3 | ||
|
|
15cdcab1fc | ||
|
|
7a1382da79 | ||
|
|
8fe0950511 | ||
|
|
4319c20363 | ||
|
|
29592cb330 | ||
|
|
8dae4f7c0b | ||
|
|
ef2a292585 | ||
|
|
ba7dc46a92 | ||
|
|
fbdb0a991a | ||
|
|
3250ec6e9c | ||
|
|
9c0aeb3af4 | ||
|
|
cd91838042 | ||
|
|
b3be3b94a0 | ||
|
|
d10fc3d265 | ||
|
|
00bea05a14 | ||
|
|
ab7acdcc3a | ||
|
|
a3bf0de651 | ||
|
|
51d6f1ca4f | ||
|
|
cb51c8729d | ||
|
|
a390daaee4 | ||
|
|
d172f7b923 | ||
|
|
4e8cf26ab6 | ||
|
|
f7820bcbaa | ||
|
|
892adf3cc1 | ||
|
|
17cbec485a | ||
|
|
5cd71f69ba | ||
|
|
8139795c64 | ||
|
|
9cb11d0859 | ||
|
|
c0bf395cde | ||
|
|
ec7b07b650 | ||
|
|
e8e4449985 | ||
|
|
3fb8659d04 | ||
|
|
43b56c22c7 | ||
|
|
861d1111c3 | ||
|
|
261cae3b6d | ||
|
|
aa4d5dd217 | ||
|
|
6e819dc4fa | ||
|
|
2cd0cd84c6 | ||
|
|
6e75da7a91 | ||
|
|
33c928c745 | ||
|
|
3f3a0609e3 | ||
|
|
998ed00729 | ||
|
|
5d3246205b | ||
|
|
13c89bf20d | ||
|
|
2dfc8417cf | ||
|
|
b7c8fab507 | ||
|
|
fb7e5e1696 | ||
|
|
3b4275b072 | ||
|
|
825e5611ba | ||
|
|
01457979b6 | ||
|
|
07655da068 | ||
|
|
ed44adc3ca | ||
|
|
4d5a91b8af | ||
|
|
4102461dd6 | ||
|
|
13d13691b5 | ||
|
|
76ba026548 | ||
|
|
f24ed2a5d1 | ||
|
|
b837b2b86c | ||
|
|
b6e28bb4d7 | ||
|
|
760fef1fc0 | ||
|
|
73732abfb2 | ||
|
|
e82f03dd88 | ||
|
|
6d14fd0b29 | ||
|
|
00563233b7 | ||
|
|
b2b0d1a8be | ||
|
|
fb1bc592f5 | ||
|
|
990456462f | ||
|
|
c65526ad57 | ||
|
|
9dfff87b69 | ||
|
|
0fc6884bc7 | ||
|
|
0c9741b70a | ||
|
|
e33dfc4f26 | ||
|
|
5aa67f0587 | ||
|
|
aef7afbe65 | ||
|
|
7c895092a7 | ||
|
|
aaa97c4441 | ||
|
|
d491329de9 | ||
|
|
9c7c669d7a | ||
|
|
a33b42035b | ||
|
|
7be95eb892 | ||
|
|
64d997ebfc | ||
|
|
26a0817c1a | ||
|
|
376487cca9 | ||
|
|
aea0d38fdd | ||
|
|
7abb7c4c79 | ||
|
|
924a92200f | ||
|
|
31bbc1f0f1 | ||
|
|
3925bb8efc | ||
|
|
32d9af559f | ||
|
|
026652a7eb | ||
|
|
3d9764f4c3 | ||
|
|
e34b633be3 | ||
|
|
1babe8cb1b | ||
|
|
1cbd1163f0 | ||
|
|
bd3983b595 | ||
|
|
520faedda0 | ||
|
|
459835d535 | ||
|
|
9b3345237a | ||
|
|
2a0cf52cfc | ||
|
|
551e5f5fd4 | ||
|
|
2a2989bb23 | ||
|
|
cbebdb4ba8 | ||
|
|
9549b05b94 | ||
|
|
5e14904fef | ||
|
|
af6b9a0967 | ||
|
|
bfe5a2c3d7 | ||
|
|
b48c9a1465 | ||
|
|
fcfabd0d90 | ||
|
|
5d02d33ee1 | ||
|
|
1544842801 | ||
|
|
88bc2bdfc9 | ||
|
|
0087651128 | ||
|
|
65d3416da5 | ||
|
|
7d48e80da5 | ||
|
|
9b22f22858 | ||
|
|
25d6e65aae | ||
|
|
96286b2a84 | ||
|
|
306931dfb1 | ||
|
|
4791501011 | ||
|
|
e0728ebcf4 | ||
|
|
97a63835af | ||
|
|
50fb37e5fe | ||
|
|
cd9f159210 | ||
|
|
3eadf887f7 | ||
|
|
9f1e9ee0ed | ||
|
|
4939f18ff7 | ||
|
|
b2ba3c6662 | ||
|
|
7bfb66d2b1 | ||
|
|
7a474855b4 | ||
|
|
88765b69e0 | ||
|
|
9951f9cf85 | ||
|
|
e6a8ef5521 | ||
|
|
7fe1a92bb3 | ||
|
|
a779d0d23a | ||
|
|
0a02acecf3 | ||
|
|
cdcdc016cc | ||
|
|
54b614d2b5 | ||
|
|
e38b86e72c | ||
|
|
7315428615 | ||
|
|
b1441c6440 | ||
|
|
940e1820f6 | ||
|
|
9c7cf1c684 | ||
|
|
4120faf289 | ||
|
|
58830990d0 | ||
|
|
13c3445163 | ||
|
|
f41e684e9a | ||
|
|
e07a75c764 | ||
|
|
2f5030c847 | ||
|
|
712055f2f8 | ||
|
|
6145f52d9c | ||
|
|
f64aa036d8 | ||
|
|
f58b2698ce | ||
|
|
a7d1c59a92 | ||
|
|
98c8c5e16e | ||
|
|
5ddfbd4b03 | ||
|
|
053887cc98 | ||
|
|
7f725f0754 | ||
|
|
7bf3020952 | ||
|
|
ad1e00b2ac | ||
|
|
f521c2ce2d | ||
|
|
ee1f0527c6 | ||
|
|
f3127df74d | ||
|
|
ebbdfc5915 | ||
|
|
dd1990a97a | ||
|
|
20376c54e2 | ||
|
|
4bcfc09acf | ||
|
|
08623228a1 | ||
|
|
d166894fef | ||
|
|
dd55f2246e | ||
|
|
78549c66c5 | ||
|
|
5000f0b2ef | ||
|
|
00a106059e | ||
|
|
9db62d408a | ||
|
|
b604064980 | ||
|
|
9019a5db93 | ||
|
|
de0eddf512 | ||
|
|
a60e1fcf7f | ||
|
|
7ac47910a2 | ||
|
|
04a9f86a85 | ||
|
|
8dd22a62a4 | ||
|
|
95a9f472d2 | ||
|
|
56fc12d6fa | ||
|
|
2b463e9b1f | ||
|
|
9910af6117 | ||
|
|
fb5e280e0d | ||
|
|
709c3be845 | ||
|
|
44932b6c41 | ||
|
|
e67e36c9eb | ||
|
|
cad6e0b3da | ||
|
|
5af42fa342 | ||
|
|
89c75b0777 | ||
|
|
84837b6e70 | ||
|
|
ca5332a9c3 | ||
|
|
a9dc8e2587 | ||
|
|
05d73aa81c | ||
|
|
c528824094 | ||
|
|
868dd3e88b | ||
|
|
c2b5446292 | ||
|
|
bbd8492c22 | ||
|
|
bf363a7135 | ||
|
|
c44d6c6c71 | ||
|
|
dfa8907a3d | ||
|
|
bb3304c6af | ||
|
|
a5a053e612 | ||
|
|
5aa30847ae | ||
|
|
ca5c07b677 | ||
|
|
8d54cda0af | ||
|
|
e63722fed4 | ||
|
|
0f95e73032 | ||
|
|
5f26cf162c | ||
|
|
b8cb8e1a65 | ||
|
|
db360d466b | ||
|
|
92581043fb | ||
|
|
8927426f78 | ||
|
|
f71b2f4338 | ||
|
|
de5fc2f515 | ||
|
|
2b0fc33114 | ||
|
|
f5a182c7e7 |
191 changed files with 6947 additions and 2756 deletions
11
.github/matrix.py
vendored
11
.github/matrix.py
vendored
|
|
@ -19,9 +19,10 @@ from packaging import version
|
||||||
#
|
#
|
||||||
# this CI is used for both development and stable branches of HAProxy
|
# this CI is used for both development and stable branches of HAProxy
|
||||||
#
|
#
|
||||||
# naming convention used, if branch name matches:
|
# naming convention used, if branch/tag name matches:
|
||||||
#
|
#
|
||||||
# "haproxy-" - stable branches
|
# "haproxy-" - stable branches
|
||||||
|
# "vX.Y.Z" - release tags
|
||||||
# otherwise - development branch (i.e. "latest" ssl variants, "latest" github images)
|
# otherwise - development branch (i.e. "latest" ssl variants, "latest" github images)
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
@ -120,11 +121,13 @@ def clean_compression(compression):
|
||||||
def main(ref_name):
|
def main(ref_name):
|
||||||
print("Generating matrix for branch '{}'.".format(ref_name))
|
print("Generating matrix for branch '{}'.".format(ref_name))
|
||||||
|
|
||||||
|
is_stable = "haproxy-" in ref_name or re.match(r'^v\d+\.\d+\.\d+$', ref_name)
|
||||||
|
|
||||||
matrix = []
|
matrix = []
|
||||||
|
|
||||||
# Ubuntu
|
# Ubuntu
|
||||||
|
|
||||||
if "haproxy-" in ref_name:
|
if is_stable:
|
||||||
os = "ubuntu-24.04" # stable branch
|
os = "ubuntu-24.04" # stable branch
|
||||||
os_arm = "ubuntu-24.04-arm" # stable branch
|
os_arm = "ubuntu-24.04-arm" # stable branch
|
||||||
else:
|
else:
|
||||||
|
|
@ -228,7 +231,7 @@ def main(ref_name):
|
||||||
# "BORINGSSL=yes",
|
# "BORINGSSL=yes",
|
||||||
]
|
]
|
||||||
|
|
||||||
if "haproxy-" not in ref_name: # development branch
|
if not is_stable: # development branch
|
||||||
ssl_versions = ssl_versions + [
|
ssl_versions = ssl_versions + [
|
||||||
"OPENSSL_VERSION=latest",
|
"OPENSSL_VERSION=latest",
|
||||||
"LIBRESSL_VERSION=latest",
|
"LIBRESSL_VERSION=latest",
|
||||||
|
|
@ -276,7 +279,7 @@ def main(ref_name):
|
||||||
)
|
)
|
||||||
|
|
||||||
# macOS on dev branches
|
# macOS on dev branches
|
||||||
if "haproxy-" not in ref_name:
|
if not is_stable:
|
||||||
os = "macos-26" # development branch
|
os = "macos-26" # development branch
|
||||||
|
|
||||||
TARGET = "osx"
|
TARGET = "osx"
|
||||||
|
|
|
||||||
3
.github/workflows/contrib.yml
vendored
3
.github/workflows/contrib.yml
vendored
|
|
@ -11,9 +11,6 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- name: Compile admin/halog/halog
|
|
||||||
run: |
|
|
||||||
make admin/halog/halog
|
|
||||||
- name: Compile dev/flags/flags
|
- name: Compile dev/flags/flags
|
||||||
run: |
|
run: |
|
||||||
make dev/flags/flags
|
make dev/flags/flags
|
||||||
|
|
|
||||||
3
.github/workflows/quic-interop-aws-lc.yml
vendored
3
.github/workflows/quic-interop-aws-lc.yml
vendored
|
|
@ -21,6 +21,9 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Update Docker to the latest
|
||||||
|
uses: docker/setup-docker-action@v4
|
||||||
|
|
||||||
- name: Build Docker image
|
- name: Build Docker image
|
||||||
id: push
|
id: push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
|
|
|
||||||
3
.github/workflows/quic-interop-libressl.yml
vendored
3
.github/workflows/quic-interop-libressl.yml
vendored
|
|
@ -21,6 +21,9 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Update Docker to the latest
|
||||||
|
uses: docker/setup-docker-action@v4
|
||||||
|
|
||||||
- name: Build Docker image
|
- name: Build Docker image
|
||||||
id: push
|
id: push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
|
|
|
||||||
244
CHANGELOG
244
CHANGELOG
|
|
@ -1,6 +1,250 @@
|
||||||
ChangeLog :
|
ChangeLog :
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
2026/03/20 : 3.4-dev7
|
||||||
|
- BUG/MINOR: stconn: Increase SC bytes_out value in se_done_ff()
|
||||||
|
- BUG/MINOR: ssl-sample: Fix sample_conv_sha2() by checking EVP_Digest* failures
|
||||||
|
- BUG/MINOR: backend: Don't get proto to use for webscoket if there is no server
|
||||||
|
- BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check
|
||||||
|
- MINOR: flt_http_comp: define and use proxy_get_comp() helper function
|
||||||
|
- MEDIUM: flt_http_comp: split "compression" filter in 2 distinct filters
|
||||||
|
- CLEANUP: flt_http_comp: comp_state doesn't bother about the direction anymore
|
||||||
|
- BUG/MINOR: admin: haproxy-reload use explicit socat address type
|
||||||
|
- MEDIUM: admin: haproxy-reload conversion to POSIX sh
|
||||||
|
- BUG/MINOR: admin: haproxy-reload rename -vv long option
|
||||||
|
- SCRIPTS: git-show-backports: hide the common ancestor warning in quiet mode
|
||||||
|
- SCRIPTS: git-show-backports: add a restart-from-last option
|
||||||
|
- MINOR: mworker: add a BUG_ON() on mproxy_li in _send_status
|
||||||
|
- BUG/MINOR: mworker: don't set the PROC_O_LEAVING flag on master process
|
||||||
|
- Revert "BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check"
|
||||||
|
- MINOR: jwt: Improve 'jwt_tokenize' function
|
||||||
|
- MINOR: jwt: Convert EC JWK to EVP_PKEY
|
||||||
|
- MINOR: jwt: Parse ec-specific fields in jose header
|
||||||
|
- MINOR: jwt: Manage ECDH-ES algorithm in jwt_decrypt_jwk function
|
||||||
|
- MINOR: jwt: Add ecdh-es+axxxkw support in jwt_decrypt_jwk converter
|
||||||
|
- MINOR: jwt: Manage ec certificates in jwt_decrypt_cert
|
||||||
|
- DOC: jwt: Add ECDH support in jwt_decrypt converters
|
||||||
|
- MINOR: stconn: Call sc_conn_process from the I/O callback if TASK_WOKEN_MSG state was set
|
||||||
|
- MINOR: mux-h2: Rely on h2s_notify_send() when resuming h2s for sending
|
||||||
|
- MINOR: mux-spop: Rely on spop_strm_notify_send() when resuming streams for sending
|
||||||
|
- MINOR: muxes: Wakup the data layer from a mux stream with TASK_WOKEN_IO state
|
||||||
|
- MAJOR: muxes: No longer use app_ops .wake() callback function from muxes
|
||||||
|
- MINOR: applet: Call sc_applet_process() instead of .wake() callback function
|
||||||
|
- MINOR: connection: Call sc_conn_process() instead of .wake() callback function
|
||||||
|
- MEDIUM: stconn: Remove .wake() callback function from app_ops
|
||||||
|
- MINOR: check: Remove wake_srv_chk() function
|
||||||
|
- MINOR: haterm: Remove hstream_wake() function
|
||||||
|
- MINOR: stconn: Wakup the SC with TASK_WOKEN_IO state from opposite side
|
||||||
|
- MEDIUM: stconn: Merge all .chk_rcv() callback functions in sc_chk_rcv()
|
||||||
|
- MINOR: stconn: Remove .chk_rcv() callback functions
|
||||||
|
- MEDIUM: stconn: Merge all .chk_snd() callback functions in sc_chk_snd()
|
||||||
|
- MINOR: stconn: Remove .chk_snd() callback functions
|
||||||
|
- MEDIUM: stconn: Merge all .abort() callback functions in sc_abort()
|
||||||
|
- MINOR: stconn: Remove .abort() callback functions
|
||||||
|
- MEDIUM: stconn: Merge all .shutdown() callback functions in sc_shutdown()
|
||||||
|
- MINOR: stconn: Remove .shutdown() callback functions
|
||||||
|
- MINOR: stconn: Totally app_ops from the stconns
|
||||||
|
- MINOR: stconn: Simplify sc_abort/sc_shutdown by merging calls to se_shutdown
|
||||||
|
- DEBUG: stconn: Add a CHECK_IF() when I/O are performed on a orphan SC
|
||||||
|
- MEDIUM: mworker: exiting when couldn't find the master mworker_proc element
|
||||||
|
- BUILD: ssl: use ASN1_STRING accessors for OpenSSL 4.0 compatibility
|
||||||
|
- BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready
|
||||||
|
- BUG/MINOR: tcpcheck: Fix typo in error error message for `http-check expect`
|
||||||
|
- BUG/MINOR: jws: fix memory leak in jws_b64_signature
|
||||||
|
- DOC: configuration: http-check expect example typo
|
||||||
|
- DOC/CLEANUP: config: update mentions of the old "Global parameters" section
|
||||||
|
- BUG/MEDIUM: ssl: Handle receiving early data with BoringSSL/AWS-LC
|
||||||
|
- BUG/MINOR: mworker: always stop the receiving listener
|
||||||
|
- BUG/MEDIUM: ssl: Don't report read data as early data with AWS-LC
|
||||||
|
- BUILD: makefile: fix range build without test command
|
||||||
|
- BUG/MINOR: memprof: avoid a small memory leak in "show profiling"
|
||||||
|
- BUG/MINOR: proxy: do not forget to validate quic-initial rules
|
||||||
|
- MINOR: activity: use dynamic allocation for "show profiling" entries
|
||||||
|
- MINOR: tools: extend the pointer hashing code to ease manipulations
|
||||||
|
- MINOR: tools: add a new pointer hash function that also takes an argument
|
||||||
|
- MINOR: memprof: attempt different retry slots for different hashes on collision
|
||||||
|
- MINOR: tinfo: start to add basic thread_exec_ctx
|
||||||
|
- MINOR: memprof: prepare to consider exec_ctx in reporting
|
||||||
|
- MINOR: memprof: also permit to sort output by calling context
|
||||||
|
- MINOR: tools: add a function to write a thread execution context.
|
||||||
|
- MINOR: debug: report the execution context on thread dumps
|
||||||
|
- MINOR: memprof: report the execution context on profiling output
|
||||||
|
- MINOR: initcall: record the file and line declaration of an INITCALL
|
||||||
|
- MINOR: tools: decode execution context TH_EX_CTX_INITCALL
|
||||||
|
- MINOR: tools: support decoding ha_caller type exec context
|
||||||
|
- MINOR: sample: store location for fetch/conv via initcalls
|
||||||
|
- MINOR: sample: also report contexts registered directly
|
||||||
|
- MINOR: tools: support an execution context that is just a function
|
||||||
|
- MINOR: actions: store the location of keywords registered via initcalls
|
||||||
|
- MINOR: actions: also report execution contexts registered directly
|
||||||
|
- MINOR: filters: set the exec context to the current filter config
|
||||||
|
- MINOR: ssl: set the thread execution context during message callbacks
|
||||||
|
- MINOR: connection: track mux calls to report their allocation context
|
||||||
|
- MINOR: task: set execution context on task/tasklet calls
|
||||||
|
- MINOR: applet: set execution context on applet calls
|
||||||
|
- MINOR: cli: keep the info of the current keyword being processed in the appctx
|
||||||
|
- MINOR: cli: keep track of the initcall context since kw registration
|
||||||
|
- MINOR: cli: implement execution context for manually registered keywords
|
||||||
|
- MINOR: activity: support aggregating by caller also for memprofile
|
||||||
|
- MINOR: activity: raise the default number of memprofile buckets to 4k
|
||||||
|
- DOC: internals: short explanation on how thread_exec_ctx works
|
||||||
|
- BUG/MINOR: mworker: only match worker processes when looking for unspawned proc
|
||||||
|
- MINOR: traces: defer processing of "-dt" options
|
||||||
|
- BUG/MINOR: mworker: fix typo &= instead of & in proc list serialization
|
||||||
|
- BUG/MINOR: mworker: set a timeout on the worker socketpair read at startup
|
||||||
|
- BUG/MINOR: mworker: avoid passing NULL version in proc list serialization
|
||||||
|
- BUG/MINOR: sockpair: set FD_CLOEXEC on fd received via SCM_RIGHTS
|
||||||
|
- BUG/MEDIUM: stconn: Don't forget to wakeup applets on shutdown
|
||||||
|
- BUG/MINOR: spoe: Properly switch SPOE filter to WAITING_ACK state
|
||||||
|
- BUG/MEDIUM: spoe: Properly abort processing on client abort
|
||||||
|
- BUG/MEDIUM: stconn: Fix abort on close when a large buffer is used
|
||||||
|
- BUG/MEDIUM: stconn: Don't perform L7 retries with large buffer
|
||||||
|
- BUG/MINOR: h2/h3: Only test number of trailers inserted in HTX message
|
||||||
|
- MINOR: htx: Add function to truncate all blocks after a specific block
|
||||||
|
- BUG/MINOR: h2/h3: Never insert partial headers/trailers in an HTX message
|
||||||
|
- BUG/MINOR: http-ana: Swap L7 buffer with request buffer by hand
|
||||||
|
- BUG/MINOR: stream: Fix crash in stream dump if the current rule has no keyword
|
||||||
|
- BUG/MINOR: mjson: make mystrtod() length-aware to prevent out-of-bounds reads
|
||||||
|
- MEDIUM: stats-file/clock: automatically update now_offset based on shared clock
|
||||||
|
- MINOR: promex: export "haproxy_sticktable_local_updates" metric
|
||||||
|
- BUG/MINOR: spoe: Fix condition to abort processing on client abort
|
||||||
|
- BUILD: spoe: Remove unsused variable
|
||||||
|
- MINOR: tools: add a function to create a tar file header
|
||||||
|
- MINOR: tools: add a function to load a file into a tar archive
|
||||||
|
- MINOR: config: support explicit "on" and "off" for "set-dumpable"
|
||||||
|
- MINOR: debug: read all libs in memory when set-dumpable=libs
|
||||||
|
- DEV: gdb: add a new utility to extract libs from a core dump: libs-from-core
|
||||||
|
- MINOR: debug: copy debug symbols from /usr/lib/debug when present
|
||||||
|
- MINOR: debug: opportunistically load libthread_db.so.1 with set-dumpable=libs
|
||||||
|
- BUG/MINOR: mworker: don't try to access an initializing process
|
||||||
|
- BUG/MEDIUM: peers: enforce check on incoming table key type
|
||||||
|
- BUG/MINOR: mux-h2: properly ignore R bit in GOAWAY stream ID
|
||||||
|
- BUG/MINOR: mux-h2: properly ignore R bit in WINDOW_UPDATE increments
|
||||||
|
- OPTIM: haterm: use chunk builders for generated response headers
|
||||||
|
- BUG/MAJOR: h3: check body size with content-length on empty FIN
|
||||||
|
- BUG/MEDIUM: h3: reject unaligned frames except DATA
|
||||||
|
- BUG/MINOR: mworker/cli: fix show proc pagination losing entries on resume
|
||||||
|
- CI: github: treat vX.Y.Z release tags as stable like haproxy-* branches
|
||||||
|
- MINOR: freq_ctr: add a function to add values with a peak
|
||||||
|
- MINOR: task: maintain a per-thread indicator of the peak run-queue size
|
||||||
|
- MINOR: mux-h2: store the concurrent streams hard limit in the h2c
|
||||||
|
- MINOR: mux-h2: permit to moderate the advertised streams limit depending on load
|
||||||
|
- MINOR: mux-h2: permit to fix a minimum value for the advertised streams limit
|
||||||
|
- BUG/MINOR: mworker: fix sort order of mworker_proc in 'show proc'
|
||||||
|
- CLEANUP: mworker: fix tab/space mess in mworker_env_to_proc_list()
|
||||||
|
|
||||||
|
2026/03/05 : 3.4-dev6
|
||||||
|
- CLEANUP: acme: remove duplicate includes
|
||||||
|
- BUG/MINOR: proxy: detect strdup error on server auto SNI
|
||||||
|
- BUG/MINOR: server: set auto SNI for dynamic servers
|
||||||
|
- BUG/MINOR: server: enable no-check-sni-auto for dynamic servers
|
||||||
|
- MINOR: haterm: provide -b and -c options (RSA key size, ECDSA curves)
|
||||||
|
- MINOR: haterm: add long options for QUIC and TCP "bind" settings
|
||||||
|
- BUG/MINOR: haterm: missing allocation check in copy_argv()
|
||||||
|
- BUG/MINOR: quic: fix counters used on BE side
|
||||||
|
- MINOR: quic: add BUG_ON() on half_open_conn counter access from BE
|
||||||
|
- BUG/MINOR: quic/h3: display QUIC/H3 backend module on HTML stats
|
||||||
|
- BUG/MINOR: acme: acme_ctx_destroy() leaks auth->dns
|
||||||
|
- BUG/MINOR: acme: wrong labels logic always memprintf errmsg
|
||||||
|
- MINOR: ssl: clarify error reporting for unsupported keywords
|
||||||
|
- BUG/MINOR: acme: fix incorrect number of arguments allowed in config
|
||||||
|
- CLEANUP: haterm: remove unreachable labels hstream_add_data()
|
||||||
|
- CLEANUP: haterm: avoid static analyzer warnings about rand() use
|
||||||
|
- CLEANUP: ssl: Remove a useless variable from ssl_gen_x509()
|
||||||
|
- CI: use the latest docker for QUIC Interop
|
||||||
|
- CI: remove redundant "halog" compilation
|
||||||
|
- CLENAUP: cfgparse: accept-invalid-http-* does not support "no"/"defaults"
|
||||||
|
- BUG/MEDIUM: spoe: Acquire context buffer in applet before consuming a frame
|
||||||
|
- MINOR: traces: always mark trace_source as thread-aligned
|
||||||
|
- MINOR: ncbmbuf: improve itbmap_next() code
|
||||||
|
- MINOR: proxy: improve code when checking server name conflicts
|
||||||
|
- MINOR: quic: add a new metric for ncbuf failures
|
||||||
|
- BUG/MINOR: haterm: cannot reset default "haterm" mode
|
||||||
|
- BUG/MEDIUM: cpu-topo: Distribute CPUs fairly across groups
|
||||||
|
- BUG/MINOR: quic: missing app ops init during backend 0-RTT sessions
|
||||||
|
- CLEANUP: ssl: remove outdated comments
|
||||||
|
- MINOR: mux-h2: also count glitches on invalid trailers
|
||||||
|
- MINOR: mux-h2: add a new setting, "tune.h2.log-errors" to tweak error logging
|
||||||
|
- BUG/MEDIUM: mux-h2: make sure to always report pending errors to the stream
|
||||||
|
- BUG/MINOR: server: adjust initialization order for dynamic servers
|
||||||
|
- CLEANUP: tree-wide: drop a few useless null-checks before free()
|
||||||
|
- CLEANUP: quic-stats: include counters from quic_stats
|
||||||
|
- REORG: stats/counters: move extra_counters to counters not stats
|
||||||
|
- CLEANUP: stats: drop stats.h / stats-t.h where not needed
|
||||||
|
- MEDIUM: counters: change the fill_stats() API to pass the module and extra_counters
|
||||||
|
- CLEANUP: counters: only retrieve zeroes for unallocated extra_counters
|
||||||
|
- MEDIUM: counters: add a dedicated storage for extra_counters in various structs
|
||||||
|
- MINOR: counters: store a tgroup step for extra_counters to access multiple tgroups
|
||||||
|
- MEDIUM: counters: store the number of thread groups accessing extra_counters
|
||||||
|
- MINOR: counters: add EXTRA_COUNTERS_BASE() to retrieve extra_counters base storage
|
||||||
|
- MEDIUM: counters: return aggregate extra counters in ->fill_stats()
|
||||||
|
- MEDIUM: counters: make EXTRA_COUNTERS_GET() consider tgid
|
||||||
|
- BUG/MINOR: call EXTRA_COUNTERS_FREE() before srv_free_params() in srv_drop()
|
||||||
|
- MINOR: promex: test applet resume in stress mode
|
||||||
|
- BUG/MINOR: promex: fix server iteration when last server is deleted
|
||||||
|
- BUG/MINOR: proxy: add dynamic backend into ID tree
|
||||||
|
- MINOR: proxy: convert proxy flags to uint
|
||||||
|
- MINOR: server: refactor srv_detach()
|
||||||
|
- MINOR: proxy: define a basic "del backend" CLI
|
||||||
|
- MINOR: proxy: define proxy watcher member
|
||||||
|
- MINOR: stats: protect proxy iteration via watcher
|
||||||
|
- MINOR: promex: use watcher to iterate over backend instances
|
||||||
|
- MINOR: lua: use watcher for proxies iterator
|
||||||
|
- MINOR: proxy: add refcount to proxies
|
||||||
|
- MINOR: proxy: rename default refcount to avoid confusion
|
||||||
|
- MINOR: server: take proxy refcount when deleting a server
|
||||||
|
- MINOR: lua: handle proxy refcount
|
||||||
|
- MINOR: proxy: prevent backend removal when unsupported
|
||||||
|
- MINOR: proxy: prevent deletion of backend referenced by config elements
|
||||||
|
- MINOR: proxy: prevent backend deletion if server still exists in it
|
||||||
|
- MINOR: server: mark backend removal as forbidden if QUIC was used
|
||||||
|
- MINOR: cli: implement wait on be-removable
|
||||||
|
- MINOR: proxy: add comment for defaults_px_ref/unref_all()
|
||||||
|
- MEDIUM: proxy: add lock for global accesses during proxy free
|
||||||
|
- MEDIUM: proxy: add lock for global accesses during default free
|
||||||
|
- MINOR: proxy: use atomic ops for default proxy refcount
|
||||||
|
- MEDIUM: proxy: implement backend deletion
|
||||||
|
- REGTESTS: add a test on "del backend"
|
||||||
|
- REGTESTS: complete "del backend" with unnamed defaults ref free
|
||||||
|
- BUG/MINOR: hlua: fix return with push nil on proxy check
|
||||||
|
- BUG/MEDIUM: stream: Handle TASK_WOKEN_RES as a stream event
|
||||||
|
- MINOR: quic: use signed char type for ALPN manipulation
|
||||||
|
- MINOR: quic/h3: reorganize stream reject after MUX closure
|
||||||
|
- MINOR: mux-quic: add function for ALPN to app-ops conversion
|
||||||
|
- MEDIUM: quic/mux-quic: adjust app-ops install
|
||||||
|
- MINOR: quic: use server cache for ALPN on BE side
|
||||||
|
- BUG/MEDIUM: hpack: correctly deal with too large decoded numbers
|
||||||
|
- BUG/MAJOR: qpack: unchecked length passed to huffman decoder
|
||||||
|
- BUG/MINOR: qpack: fix 1-byte OOB read in qpack_decode_fs_pfx()
|
||||||
|
- BUG/MINOR: quic: fix OOB read in preferred_address transport parameter
|
||||||
|
- BUG/MEDIUM: qpack: correctly deal with too large decoded numbers
|
||||||
|
- BUG/MINOR: hlua: Properly enable/disable line receives from HTTP applet
|
||||||
|
- BUG/MEDIUM: hlua: Fix end of request detection when retrieving payload
|
||||||
|
- BUG/MINOR: hlua: Properly enable/disable receives for TCP applets
|
||||||
|
- MINOR: htx: Add a function to retrieve the HTTP version from a start-line
|
||||||
|
- MINOR: h1-htx: Reports non-HTTP version via dedicated flags
|
||||||
|
- BUG/MINOR: h1-htx: Be sure that H1 response version starts by "HTTP/"
|
||||||
|
- MINOR: http-ana: Save the message version in the http_msg structure
|
||||||
|
- MEDIUM: http-fetch: Rework how HTTP message version is retrieved
|
||||||
|
- MEDIUM: http-ana: Use the version of the opposite side for internal messages
|
||||||
|
- DEBUG: stream: Display the currently running rule in stream dump
|
||||||
|
- MINOR: filters: Use filter API as far as poissible to break loops on filters
|
||||||
|
- MINOR: filters: Set last_entity when a filter fails on stream_start callback
|
||||||
|
- MINOR: stream: Display the currently running filter per channel in stream dump
|
||||||
|
- DOC: config: Use the right alias for %B
|
||||||
|
- BUG/MINOR: channel: Increase the stconn bytes_in value in channel_add_input()
|
||||||
|
- BUG/MINOR: sample: Fix sample to retrieve the number of bytes received and sent
|
||||||
|
- BUG/MINOR: http-ana: Increment scf bytes_out value if an haproxy error is sent
|
||||||
|
- BUG/MAJOR: fcgi: Fix param decoding by properly checking its size
|
||||||
|
- BUG/MAJOR: resolvers: Properly lowered the names found in DNS response
|
||||||
|
- BUG/MEDIUM: mux-fcgi: Use a safe loop to resume each stream eligible for sending
|
||||||
|
- MINOR: mux-fcgi: Use a dedicated function to resume streams eligible for sending
|
||||||
|
- CLEANUP: qpack: simplify length checks in qpack_decode_fs()
|
||||||
|
- MINOR: counters: Introduce COUNTERS_UPDATE_MAX()
|
||||||
|
- MINOR: listeners: Update the frequency counters separately when needed
|
||||||
|
- MINOR: proxies: Update beconn separately
|
||||||
|
- MINOR: stats: Add an option to disable the calculation of max counters
|
||||||
|
|
||||||
2026/02/19 : 3.4-dev5
|
2026/02/19 : 3.4-dev5
|
||||||
- DOC: internals: addd mworker V3 internals
|
- DOC: internals: addd mworker V3 internals
|
||||||
- BUG/MINOR: threads: Initialize maxthrpertgroup earlier.
|
- BUG/MINOR: threads: Initialize maxthrpertgroup earlier.
|
||||||
|
|
|
||||||
10
Makefile
10
Makefile
|
|
@ -1043,7 +1043,7 @@ IGNORE_OPTS=help install install-man install-doc install-bin \
|
||||||
uninstall clean tags cscope tar git-tar version update-version \
|
uninstall clean tags cscope tar git-tar version update-version \
|
||||||
opts reg-tests reg-tests-help unit-tests admin/halog/halog dev/flags/flags \
|
opts reg-tests reg-tests-help unit-tests admin/halog/halog dev/flags/flags \
|
||||||
dev/haring/haring dev/ncpu/ncpu dev/poll/poll dev/tcploop/tcploop \
|
dev/haring/haring dev/ncpu/ncpu dev/poll/poll dev/tcploop/tcploop \
|
||||||
dev/term_events/term_events dev/gdb/pm-from-core
|
dev/term_events/term_events dev/gdb/pm-from-core dev/gdb/libs-from-core
|
||||||
|
|
||||||
ifneq ($(TARGET),)
|
ifneq ($(TARGET),)
|
||||||
ifeq ($(filter $(firstword $(MAKECMDGOALS)),$(IGNORE_OPTS)),)
|
ifeq ($(filter $(firstword $(MAKECMDGOALS)),$(IGNORE_OPTS)),)
|
||||||
|
|
@ -1077,6 +1077,9 @@ admin/dyncookie/dyncookie: admin/dyncookie/dyncookie.o
|
||||||
dev/flags/flags: dev/flags/flags.o
|
dev/flags/flags: dev/flags/flags.o
|
||||||
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
|
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
|
||||||
|
|
||||||
|
dev/gdb/libs-from-core: dev/gdb/libs-from-core.o
|
||||||
|
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
|
||||||
|
|
||||||
dev/gdb/pm-from-core: dev/gdb/pm-from-core.o
|
dev/gdb/pm-from-core: dev/gdb/pm-from-core.o
|
||||||
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
|
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
|
||||||
|
|
||||||
|
|
@ -1178,7 +1181,7 @@ distclean: clean
|
||||||
$(Q)rm -f admin/dyncookie/dyncookie
|
$(Q)rm -f admin/dyncookie/dyncookie
|
||||||
$(Q)rm -f dev/haring/haring dev/ncpu/ncpu{,.so} dev/poll/poll dev/tcploop/tcploop
|
$(Q)rm -f dev/haring/haring dev/ncpu/ncpu{,.so} dev/poll/poll dev/tcploop/tcploop
|
||||||
$(Q)rm -f dev/hpack/decode dev/hpack/gen-enc dev/hpack/gen-rht
|
$(Q)rm -f dev/hpack/decode dev/hpack/gen-enc dev/hpack/gen-rht
|
||||||
$(Q)rm -f dev/qpack/decode dev/gdb/pm-from-core
|
$(Q)rm -f dev/qpack/decode dev/gdb/pm-from-core dev/gdb/libs-from-core
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
$(Q)find src include \( -name '*.c' -o -name '*.h' \) -print0 | \
|
$(Q)find src include \( -name '*.c' -o -name '*.h' \) -print0 | \
|
||||||
|
|
@ -1332,7 +1335,8 @@ range:
|
||||||
echo "[ $$index/$$count ] $$commit #############################"; \
|
echo "[ $$index/$$count ] $$commit #############################"; \
|
||||||
git checkout -q $$commit || die 1; \
|
git checkout -q $$commit || die 1; \
|
||||||
$(MAKE) all || die 1; \
|
$(MAKE) all || die 1; \
|
||||||
[ -z "$(TEST_CMD)" ] || $(TEST_CMD) || die 1; \
|
set -- $(TEST_CMD); \
|
||||||
|
[ "$$#" -eq 0 ] || "$$@" || die 1; \
|
||||||
index=$$((index + 1)); \
|
index=$$((index + 1)); \
|
||||||
done; \
|
done; \
|
||||||
echo;echo "Done! $${count} commit(s) built successfully for RANGE $${RANGE}" ; \
|
echo;echo "Done! $${count} commit(s) built successfully for RANGE $${RANGE}" ; \
|
||||||
|
|
|
||||||
2
VERDATE
2
VERDATE
|
|
@ -1,2 +1,2 @@
|
||||||
$Format:%ci$
|
$Format:%ci$
|
||||||
2026/02/19
|
2026/03/20
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
3.4-dev5
|
3.4-dev7
|
||||||
|
|
|
||||||
|
|
@ -407,6 +407,7 @@ listed below. Metrics from extra counters are not listed.
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
| haproxy_sticktable_size |
|
| haproxy_sticktable_size |
|
||||||
| haproxy_sticktable_used |
|
| haproxy_sticktable_used |
|
||||||
|
| haproxy_sticktable_local_updates |
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
|
|
||||||
* Resolvers metrics
|
* Resolvers metrics
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include <haproxy/stats.h>
|
#include <haproxy/stats.h>
|
||||||
#include <haproxy/stconn.h>
|
#include <haproxy/stconn.h>
|
||||||
#include <haproxy/stream.h>
|
#include <haproxy/stream.h>
|
||||||
|
#include <haproxy/stress.h>
|
||||||
#include <haproxy/task.h>
|
#include <haproxy/task.h>
|
||||||
#include <haproxy/tools.h>
|
#include <haproxy/tools.h>
|
||||||
#include <haproxy/version.h>
|
#include <haproxy/version.h>
|
||||||
|
|
@ -82,6 +83,7 @@ struct promex_ctx {
|
||||||
unsigned field_num; /* current field number (ST_I_PX_* etc) */
|
unsigned field_num; /* current field number (ST_I_PX_* etc) */
|
||||||
unsigned mod_field_num; /* first field number of the current module (ST_I_PX_* etc) */
|
unsigned mod_field_num; /* first field number of the current module (ST_I_PX_* etc) */
|
||||||
int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */
|
int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */
|
||||||
|
struct watcher px_watch; /* watcher to automatically update next pointer */
|
||||||
struct watcher srv_watch; /* watcher to automatically update next pointer */
|
struct watcher srv_watch; /* watcher to automatically update next pointer */
|
||||||
struct list modules; /* list of promex modules to export */
|
struct list modules; /* list of promex modules to export */
|
||||||
struct eb_root filters; /* list of filters to apply on metrics name */
|
struct eb_root filters; /* list of filters to apply on metrics name */
|
||||||
|
|
@ -347,6 +349,10 @@ static int promex_dump_ts(struct appctx *appctx, struct ist prefix,
|
||||||
istcat(&n, prefix, PROMEX_MAX_NAME_LEN);
|
istcat(&n, prefix, PROMEX_MAX_NAME_LEN);
|
||||||
istcat(&n, name, PROMEX_MAX_NAME_LEN);
|
istcat(&n, name, PROMEX_MAX_NAME_LEN);
|
||||||
|
|
||||||
|
/* In stress mode, force yielding on each metric. */
|
||||||
|
if (STRESS_RUN1(istlen(*out), 0))
|
||||||
|
goto full;
|
||||||
|
|
||||||
if ((ctx->flags & PROMEX_FL_METRIC_HDR) &&
|
if ((ctx->flags & PROMEX_FL_METRIC_HDR) &&
|
||||||
!promex_dump_ts_header(n, desc, type, out, max))
|
!promex_dump_ts_header(n, desc, type, out, max))
|
||||||
goto full;
|
goto full;
|
||||||
|
|
@ -626,8 +632,6 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||||
void *counters;
|
|
||||||
|
|
||||||
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_FE))
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_FE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -664,8 +668,7 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
|
||||||
goto next_px2;
|
goto next_px2;
|
||||||
|
|
||||||
counters = EXTRA_COUNTERS_GET(px->extra_counters_fe, mod);
|
if (!mod->fill_stats(mod, px->extra_counters_fe, stats + ctx->field_num, &ctx->mod_field_num))
|
||||||
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
val = stats[ctx->field_num + ctx->mod_field_num];
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
||||||
|
|
@ -817,8 +820,6 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||||
void *counters;
|
|
||||||
|
|
||||||
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_LI))
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_LI))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -864,8 +865,7 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
labels[lb_idx+1].name = ist("mod");
|
labels[lb_idx+1].name = ist("mod");
|
||||||
labels[lb_idx+1].value = ist2(mod->name, strlen(mod->name));
|
labels[lb_idx+1].value = ist2(mod->name, strlen(mod->name));
|
||||||
|
|
||||||
counters = EXTRA_COUNTERS_GET(li->extra_counters, mod);
|
if (!mod->fill_stats(mod, li->extra_counters, stats + ctx->field_num, &ctx->mod_field_num))
|
||||||
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
val = stats[ctx->field_num + ctx->mod_field_num];
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
||||||
|
|
@ -941,9 +941,6 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if (promex_filter_metric(appctx, prefix, name))
|
if (promex_filter_metric(appctx, prefix, name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!px)
|
|
||||||
px = proxies_list;
|
|
||||||
|
|
||||||
while (px) {
|
while (px) {
|
||||||
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
||||||
unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 };
|
unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 };
|
||||||
|
|
@ -1098,9 +1095,16 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
&val, labels, &out, max))
|
&val, labels, &out, max))
|
||||||
goto full;
|
goto full;
|
||||||
next_px:
|
next_px:
|
||||||
px = px->next;
|
px = watcher_next(&ctx->px_watch, px->next);
|
||||||
}
|
}
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
||||||
|
|
||||||
|
/* Prepare a new iteration for the next stat column.
|
||||||
|
* Update ctx.p[0] via watcher.
|
||||||
|
*/
|
||||||
|
watcher_attach(&ctx->px_watch, proxies_list);
|
||||||
|
px = proxies_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip extra counters */
|
/* Skip extra counters */
|
||||||
|
|
@ -1113,8 +1117,6 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||||
void *counters;
|
|
||||||
|
|
||||||
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_BE))
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_BE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -1125,9 +1127,6 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if (promex_filter_metric(appctx, prefix, name))
|
if (promex_filter_metric(appctx, prefix, name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!px)
|
|
||||||
px = proxies_list;
|
|
||||||
|
|
||||||
while (px) {
|
while (px) {
|
||||||
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
||||||
struct promex_metric metric;
|
struct promex_metric metric;
|
||||||
|
|
@ -1151,8 +1150,7 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
||||||
goto next_px2;
|
goto next_px2;
|
||||||
|
|
||||||
counters = EXTRA_COUNTERS_GET(px->extra_counters_be, mod);
|
if (!mod->fill_stats(mod, px->extra_counters_be, stats + ctx->field_num, &ctx->mod_field_num))
|
||||||
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
val = stats[ctx->field_num + ctx->mod_field_num];
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
||||||
|
|
@ -1163,25 +1161,39 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
goto full;
|
goto full;
|
||||||
|
|
||||||
next_px2:
|
next_px2:
|
||||||
px = px->next;
|
px = watcher_next(&ctx->px_watch, px->next);
|
||||||
}
|
}
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
||||||
|
|
||||||
|
/* Prepare a new iteration for the next stat column.
|
||||||
|
* Update ctx.p[0] via watcher.
|
||||||
|
*/
|
||||||
|
watcher_attach(&ctx->px_watch, proxies_list);
|
||||||
|
px = proxies_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->field_num += mod->stats_count;
|
ctx->field_num += mod->stats_count;
|
||||||
ctx->mod_field_num = 0;
|
ctx->mod_field_num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
px = NULL;
|
|
||||||
mod = NULL;
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
if (ret) {
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
|
mod = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (out.len) {
|
if (out.len) {
|
||||||
if (!htx_add_data_atonce(htx, out))
|
if (!htx_add_data_atonce(htx, out)) {
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
return -1; /* Unexpected and unrecoverable error */
|
return -1; /* Unexpected and unrecoverable error */
|
||||||
}
|
}
|
||||||
/* Save pointers (0=current proxy, 1=current stats module) of the current context */
|
}
|
||||||
ctx->p[0] = px;
|
|
||||||
|
/* Save pointers of the current context for dump resumption :
|
||||||
|
* 0=current proxy, 1=current stats module
|
||||||
|
* Note that p[0] is already automatically updated via px_watch.
|
||||||
|
*/
|
||||||
ctx->p[1] = mod;
|
ctx->p[1] = mod;
|
||||||
return ret;
|
return ret;
|
||||||
full:
|
full:
|
||||||
|
|
@ -1223,9 +1235,6 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if (promex_filter_metric(appctx, prefix, name))
|
if (promex_filter_metric(appctx, prefix, name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!px)
|
|
||||||
px = proxies_list;
|
|
||||||
|
|
||||||
while (px) {
|
while (px) {
|
||||||
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
||||||
enum promex_mt_type type;
|
enum promex_mt_type type;
|
||||||
|
|
@ -1245,11 +1254,6 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
||||||
goto next_px;
|
goto next_px;
|
||||||
|
|
||||||
if (!sv) {
|
|
||||||
watcher_attach(&ctx->srv_watch, px->srv);
|
|
||||||
sv = px->srv;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (sv) {
|
while (sv) {
|
||||||
labels[lb_idx].name = ist("server");
|
labels[lb_idx].name = ist("server");
|
||||||
labels[lb_idx].value = ist2(sv->id, strlen(sv->id));
|
labels[lb_idx].value = ist2(sv->id, strlen(sv->id));
|
||||||
|
|
@ -1405,9 +1409,25 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
|
|
||||||
next_px:
|
next_px:
|
||||||
watcher_detach(&ctx->srv_watch);
|
watcher_detach(&ctx->srv_watch);
|
||||||
px = px->next;
|
px = watcher_next(&ctx->px_watch, px->next);
|
||||||
|
if (px) {
|
||||||
|
/* Update ctx.p[1] via watcher. */
|
||||||
|
watcher_attach(&ctx->srv_watch, px->srv);
|
||||||
|
sv = ctx->p[1];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
||||||
|
|
||||||
|
/* Prepare a new iteration for the next stat column.
|
||||||
|
* Update ctx.p[0]/p[1] via px_watch/srv_watch.
|
||||||
|
*/
|
||||||
|
watcher_attach(&ctx->px_watch, proxies_list);
|
||||||
|
px = proxies_list;
|
||||||
|
if (likely(px)) {
|
||||||
|
watcher_attach(&ctx->srv_watch, px->srv);
|
||||||
|
sv = ctx->p[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip extra counters */
|
/* Skip extra counters */
|
||||||
|
|
@ -1420,8 +1440,6 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||||
void *counters;
|
|
||||||
|
|
||||||
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_SRV))
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_SRV))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -1432,9 +1450,6 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if (promex_filter_metric(appctx, prefix, name))
|
if (promex_filter_metric(appctx, prefix, name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!px)
|
|
||||||
px = proxies_list;
|
|
||||||
|
|
||||||
while (px) {
|
while (px) {
|
||||||
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
||||||
struct promex_metric metric;
|
struct promex_metric metric;
|
||||||
|
|
@ -1455,11 +1470,6 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
||||||
goto next_px2;
|
goto next_px2;
|
||||||
|
|
||||||
if (!sv) {
|
|
||||||
watcher_attach(&ctx->srv_watch, px->srv);
|
|
||||||
sv = px->srv;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (sv) {
|
while (sv) {
|
||||||
labels[lb_idx].name = ist("server");
|
labels[lb_idx].name = ist("server");
|
||||||
labels[lb_idx].value = ist2(sv->id, strlen(sv->id));
|
labels[lb_idx].value = ist2(sv->id, strlen(sv->id));
|
||||||
|
|
@ -1471,8 +1481,7 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
goto next_sv2;
|
goto next_sv2;
|
||||||
|
|
||||||
|
|
||||||
counters = EXTRA_COUNTERS_GET(sv->extra_counters, mod);
|
if (!mod->fill_stats(mod, sv->extra_counters, stats + ctx->field_num, &ctx->mod_field_num))
|
||||||
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
val = stats[ctx->field_num + ctx->mod_field_num];
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
||||||
|
|
@ -1488,28 +1497,47 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
|
|
||||||
next_px2:
|
next_px2:
|
||||||
watcher_detach(&ctx->srv_watch);
|
watcher_detach(&ctx->srv_watch);
|
||||||
px = px->next;
|
px = watcher_next(&ctx->px_watch, px->next);
|
||||||
|
if (px) {
|
||||||
|
/* Update ctx.p[1] via watcher. */
|
||||||
|
watcher_attach(&ctx->srv_watch, px->srv);
|
||||||
|
sv = ctx->p[1];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
||||||
|
|
||||||
|
/* Prepare a new iteration for the next stat column.
|
||||||
|
* Update ctx.p[0]/p[1] via px_watch/srv_watch.
|
||||||
|
*/
|
||||||
|
watcher_attach(&ctx->px_watch, proxies_list);
|
||||||
|
px = proxies_list;
|
||||||
|
if (likely(px)) {
|
||||||
|
watcher_attach(&ctx->srv_watch, px->srv);
|
||||||
|
sv = ctx->p[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->field_num += mod->stats_count;
|
ctx->field_num += mod->stats_count;
|
||||||
ctx->mod_field_num = 0;
|
ctx->mod_field_num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
px = NULL;
|
|
||||||
sv = NULL;
|
|
||||||
mod = NULL;
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
if (ret) {
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
|
watcher_detach(&ctx->srv_watch);
|
||||||
|
mod = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (out.len) {
|
if (out.len) {
|
||||||
if (!htx_add_data_atonce(htx, out))
|
if (!htx_add_data_atonce(htx, out))
|
||||||
return -1; /* Unexpected and unrecoverable error */
|
return -1; /* Unexpected and unrecoverable error */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save pointers (0=current proxy, 1=current server, 2=current stats module) of the current context */
|
/* Save pointers of the current context for dump resumption :
|
||||||
ctx->p[0] = px;
|
* 0=current proxy, 1=current server, 2=current stats module
|
||||||
ctx->p[1] = sv;
|
* Note that p[0]/p[1] are already automatically updated via px_watch/srv_watch.
|
||||||
|
*/
|
||||||
ctx->p[2] = mod;
|
ctx->p[2] = mod;
|
||||||
return ret;
|
return ret;
|
||||||
full:
|
full:
|
||||||
|
|
@ -1517,6 +1545,7 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
watcher_detach(&ctx->srv_watch);
|
watcher_detach(&ctx->srv_watch);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -1739,6 +1768,11 @@ static int promex_dump_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
ctx->field_num = ST_I_PX_PXNAME;
|
ctx->field_num = ST_I_PX_PXNAME;
|
||||||
ctx->mod_field_num = 0;
|
ctx->mod_field_num = 0;
|
||||||
appctx->st1 = PROMEX_DUMPER_BACK;
|
appctx->st1 = PROMEX_DUMPER_BACK;
|
||||||
|
|
||||||
|
if (ctx->flags & PROMEX_FL_SCOPE_BACK) {
|
||||||
|
/* Update ctx.p[0] via watcher. */
|
||||||
|
watcher_attach(&ctx->px_watch, proxies_list);
|
||||||
|
}
|
||||||
__fallthrough;
|
__fallthrough;
|
||||||
|
|
||||||
case PROMEX_DUMPER_BACK:
|
case PROMEX_DUMPER_BACK:
|
||||||
|
|
@ -1756,6 +1790,15 @@ static int promex_dump_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
ctx->field_num = ST_I_PX_PXNAME;
|
ctx->field_num = ST_I_PX_PXNAME;
|
||||||
ctx->mod_field_num = 0;
|
ctx->mod_field_num = 0;
|
||||||
appctx->st1 = PROMEX_DUMPER_SRV;
|
appctx->st1 = PROMEX_DUMPER_SRV;
|
||||||
|
|
||||||
|
if (ctx->flags & PROMEX_FL_SCOPE_SERVER) {
|
||||||
|
/* Update ctx.p[0] via watcher. */
|
||||||
|
watcher_attach(&ctx->px_watch, proxies_list);
|
||||||
|
if (likely(proxies_list)) {
|
||||||
|
/* Update ctx.p[1] via watcher. */
|
||||||
|
watcher_attach(&ctx->srv_watch, proxies_list->srv);
|
||||||
|
}
|
||||||
|
}
|
||||||
__fallthrough;
|
__fallthrough;
|
||||||
|
|
||||||
case PROMEX_DUMPER_SRV:
|
case PROMEX_DUMPER_SRV:
|
||||||
|
|
@ -2033,6 +2076,7 @@ static int promex_appctx_init(struct appctx *appctx)
|
||||||
LIST_INIT(&ctx->modules);
|
LIST_INIT(&ctx->modules);
|
||||||
ctx->filters = EB_ROOT;
|
ctx->filters = EB_ROOT;
|
||||||
appctx->st0 = PROMEX_ST_INIT;
|
appctx->st0 = PROMEX_ST_INIT;
|
||||||
|
watcher_init(&ctx->px_watch, &ctx->p[0], offsetof(struct proxy, watcher_list));
|
||||||
watcher_init(&ctx->srv_watch, &ctx->p[1], offsetof(struct server, watcher_list));
|
watcher_init(&ctx->srv_watch, &ctx->p[1], offsetof(struct server, watcher_list));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -2047,6 +2091,11 @@ static void promex_appctx_release(struct appctx *appctx)
|
||||||
struct promex_metric_filter *flt;
|
struct promex_metric_filter *flt;
|
||||||
struct eb32_node *node, *next;
|
struct eb32_node *node, *next;
|
||||||
|
|
||||||
|
if (appctx->st1 == PROMEX_DUMPER_BACK ||
|
||||||
|
appctx->st1 == PROMEX_DUMPER_SRV) {
|
||||||
|
watcher_detach(&ctx->px_watch);
|
||||||
|
}
|
||||||
|
|
||||||
if (appctx->st1 == PROMEX_DUMPER_SRV)
|
if (appctx->st1 == PROMEX_DUMPER_SRV)
|
||||||
watcher_detach(&ctx->srv_watch);
|
watcher_detach(&ctx->srv_watch);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
export VERBOSE=1
|
export VERBOSE=1
|
||||||
export TIMEOUT=90
|
export TIMEOUT=90
|
||||||
export MASTER_SOCKET=${MASTER_SOCKET:-/var/run/haproxy-master.sock}
|
export MASTER_SOCKET="${MASTER_SOCKET:-/var/run/haproxy-master.sock}"
|
||||||
export RET=
|
|
||||||
|
|
||||||
alert() {
|
alert() {
|
||||||
if [ "$VERBOSE" -ge "1" ]; then
|
if [ "$VERBOSE" -ge "1" ]; then
|
||||||
|
|
@ -15,32 +14,38 @@ alert() {
|
||||||
|
|
||||||
|
|
||||||
reload() {
|
reload() {
|
||||||
while read -r line; do
|
if [ -S "$MASTER_SOCKET" ]; then
|
||||||
|
socat_addr="UNIX-CONNECT:${MASTER_SOCKET}"
|
||||||
if [ "$line" = "Success=0" ]; then
|
|
||||||
RET=1
|
|
||||||
elif [ "$line" = "Success=1" ]; then
|
|
||||||
RET=0
|
|
||||||
elif [ "$line" = "Another reload is still in progress." ]; then
|
|
||||||
alert "$line"
|
|
||||||
elif [ "$line" = "--" ]; then
|
|
||||||
continue;
|
|
||||||
else
|
else
|
||||||
if [ "$RET" = 1 ] && [ "$VERBOSE" = "2" ]; then
|
case "$MASTER_SOCKET" in
|
||||||
echo "$line" >&2
|
*:[0-9]*)
|
||||||
elif [ "$VERBOSE" = "3" ]; then
|
socat_addr="TCP:${MASTER_SOCKET}"
|
||||||
echo "$line" >&2
|
;;
|
||||||
fi
|
*)
|
||||||
fi
|
alert "Invalid master socket address '${MASTER_SOCKET}': expected a UNIX socket file or <host>:<port>"
|
||||||
|
|
||||||
done < <(echo "reload" | socat -t"${TIMEOUT}" "${MASTER_SOCKET}" -)
|
|
||||||
|
|
||||||
if [ -z "$RET" ]; then
|
|
||||||
alert "Couldn't finish the reload before the timeout (${TIMEOUT})."
|
|
||||||
return 1
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return "$RET"
|
echo "reload" | socat -t"${TIMEOUT}" "$socat_addr" - | {
|
||||||
|
read -r status || { alert "No status received (connection error or timeout after ${TIMEOUT}s)."; exit 1; }
|
||||||
|
case "$status" in
|
||||||
|
"Success=1") ret=0 ;;
|
||||||
|
"Success=0") ret=1 ;;
|
||||||
|
*) alert "Unexpected response: '$status'"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
read -r _ # consume "--"
|
||||||
|
|
||||||
|
if [ "$VERBOSE" -ge 3 ] || { [ "$ret" = 1 ] && [ "$VERBOSE" -ge 2 ]; }; then
|
||||||
|
cat >&2
|
||||||
|
else
|
||||||
|
cat >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit "$ret"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
|
|
@ -52,12 +57,12 @@ usage() {
|
||||||
echo " EXPERIMENTAL script!"
|
echo " EXPERIMENTAL script!"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo " -S, --master-socket <path> Use the master socket at <path> (default: ${MASTER_SOCKET})"
|
echo " -S, --master-socket <addr> Unix socket path or <host>:<port> (default: ${MASTER_SOCKET})"
|
||||||
echo " -d, --debug Debug mode, set -x"
|
echo " -d, --debug Debug mode, set -x"
|
||||||
echo " -t, --timeout Timeout (socat -t) (default: ${TIMEOUT})"
|
echo " -t, --timeout Timeout (socat -t) (default: ${TIMEOUT})"
|
||||||
echo " -s, --silent Silent mode (no output)"
|
echo " -s, --silent Silent mode (no output)"
|
||||||
echo " -v, --verbose Verbose output (output from haproxy on failure)"
|
echo " -v, --verbose Verbose output (output from haproxy on failure)"
|
||||||
echo " -vv Even more verbose output (output from haproxy on success and failure)"
|
echo " -vv --verbose=all Very verbose output (output from haproxy on success and failure)"
|
||||||
echo " -h, --help This help"
|
echo " -h, --help This help"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Examples:"
|
echo "Examples:"
|
||||||
|
|
@ -84,7 +89,7 @@ main() {
|
||||||
VERBOSE=2
|
VERBOSE=2
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-vv|--verbose)
|
-vv|--verbose=all)
|
||||||
VERBOSE=3
|
VERBOSE=3
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
162
dev/gdb/libs-from-core.c
Normal file
162
dev/gdb/libs-from-core.c
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Extracts the libs archives from a core dump
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Willy Tarreau <w@1wt.eu>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note: builds with no option under glibc, and can be built as a minimal
|
||||||
|
* uploadable static executable using nolibc as well:
|
||||||
|
gcc -o libs-from-core -nostdinc -nostdlib -s -Os -static -fno-ident \
|
||||||
|
-fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables \
|
||||||
|
-Wl,--gc-sections,--orphan-handling=discard,-znoseparate-code \
|
||||||
|
-I /path/to/nolibc-sysroot/include libs-from-core.c
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void usage(const char *progname)
|
||||||
|
{
|
||||||
|
const char *slash = strrchr(progname, '/');
|
||||||
|
|
||||||
|
if (slash)
|
||||||
|
progname = slash + 1;
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"Usage: %s [-q] <core_file>\n"
|
||||||
|
"Locate a libs archive from an haproxy core dump and dump it to stdout.\n"
|
||||||
|
"Arguments:\n"
|
||||||
|
" -q Query mode: only report offset and length, do not dump\n"
|
||||||
|
" core_file Core dump produced by haproxy\n",
|
||||||
|
progname);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Elf64_Ehdr *ehdr;
|
||||||
|
Elf64_Phdr *phdr;
|
||||||
|
struct stat st;
|
||||||
|
uint8_t *mem;
|
||||||
|
int i, fd;
|
||||||
|
const char *fname;
|
||||||
|
int quiet = 0;
|
||||||
|
int arg;
|
||||||
|
|
||||||
|
for (arg = 1; arg < argc; arg++) {
|
||||||
|
if (*argv[arg] != '-')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (strcmp(argv[arg], "-q") == 0)
|
||||||
|
quiet = 1;
|
||||||
|
else if (strcmp(argv[arg], "--") == 0) {
|
||||||
|
arg++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg < argc) {
|
||||||
|
fname = argv[arg];
|
||||||
|
} else {
|
||||||
|
usage(argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(fname, O_RDONLY);
|
||||||
|
|
||||||
|
/* Let's just map the core dump as an ELF header */
|
||||||
|
fstat(fd, &st);
|
||||||
|
mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
if (mem == MAP_FAILED) {
|
||||||
|
perror("mmap()");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the program headers */
|
||||||
|
ehdr = (Elf64_Ehdr *)mem;
|
||||||
|
|
||||||
|
/* check that it's really a core. Should be "\x7fELF" */
|
||||||
|
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
|
||||||
|
fprintf(stderr, "ELF magic not found.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
|
||||||
|
fprintf(stderr, "Only 64-bit ELF supported.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ehdr->e_type != ET_CORE) {
|
||||||
|
fprintf(stderr, "ELF type %d, not a core dump.\n", ehdr->e_type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OK we can safely go with program headers */
|
||||||
|
phdr = (Elf64_Phdr *)(mem + ehdr->e_phoff);
|
||||||
|
|
||||||
|
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||||
|
uint64_t size = phdr[i].p_filesz;
|
||||||
|
uint64_t offset = phdr[i].p_offset;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (phdr[i].p_type != PT_LOAD)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//fprintf(stderr, "Scanning segment %d...\n", ehdr->e_phnum);
|
||||||
|
//fprintf(stderr, "\r%-5d: off=%lx va=%lx sz=%lx ", i, (long)offset, (long)phdr[i].p_vaddr, (long)size);
|
||||||
|
if (!size)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (size < 512) // minimum for a tar header
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* tar magic */
|
||||||
|
if (memcmp(mem + offset + 257, "ustar\0""00", 8) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* uid, gid */
|
||||||
|
if (memcmp(mem + offset + 108, "0000000\0""0000000\0", 16) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* link name */
|
||||||
|
if (memcmp(mem + offset + 157, "haproxy-libs-dump\0", 18) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* OK that's really it */
|
||||||
|
|
||||||
|
if (quiet)
|
||||||
|
printf("offset=%#lx size=%#lx\n", offset, size);
|
||||||
|
else
|
||||||
|
ret = (write(1, mem + offset, size) == size) ? 0 : 1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
//fprintf(stderr, "\r%75s\n", "\r");
|
||||||
|
fprintf(stderr, "libs archive not found. Was 'set-dumpable' set to 'libs' ?\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Configuration Manual
|
Configuration Manual
|
||||||
----------------------
|
----------------------
|
||||||
version 3.4
|
version 3.4
|
||||||
2026/02/19
|
2026/03/20
|
||||||
|
|
||||||
|
|
||||||
This document covers the configuration language as implemented in the version
|
This document covers the configuration language as implemented in the version
|
||||||
|
|
@ -1725,7 +1725,7 @@ Assuming haproxy is in $PATH, test these configurations in a shell with:
|
||||||
$ sudo haproxy -f configuration.conf -c
|
$ sudo haproxy -f configuration.conf -c
|
||||||
|
|
||||||
|
|
||||||
3. Global parameters
|
3. Global section
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
Parameters in the "global" section are process-wide and often OS-specific. They
|
Parameters in the "global" section are process-wide and often OS-specific. They
|
||||||
|
|
@ -1886,10 +1886,13 @@ The following keywords are supported in the "global" section :
|
||||||
- tune.h2.be.glitches-threshold
|
- tune.h2.be.glitches-threshold
|
||||||
- tune.h2.be.initial-window-size
|
- tune.h2.be.initial-window-size
|
||||||
- tune.h2.be.max-concurrent-streams
|
- tune.h2.be.max-concurrent-streams
|
||||||
|
- tune.h2.be.max-frames-at-once
|
||||||
- tune.h2.be.rxbuf
|
- tune.h2.be.rxbuf
|
||||||
- tune.h2.fe.glitches-threshold
|
- tune.h2.fe.glitches-threshold
|
||||||
- tune.h2.fe.initial-window-size
|
- tune.h2.fe.initial-window-size
|
||||||
- tune.h2.fe.max-concurrent-streams
|
- tune.h2.fe.max-concurrent-streams
|
||||||
|
- tune.h2.fe.max-frames-at-once
|
||||||
|
- tune.h2.fe.max-rst-at-once
|
||||||
- tune.h2.fe.max-total-streams
|
- tune.h2.fe.max-total-streams
|
||||||
- tune.h2.fe.rxbuf
|
- tune.h2.fe.rxbuf
|
||||||
- tune.h2.header-table-size
|
- tune.h2.header-table-size
|
||||||
|
|
@ -3148,10 +3151,29 @@ server-state-file <file>
|
||||||
configuration. See also "server-state-base" and "show servers state",
|
configuration. See also "server-state-base" and "show servers state",
|
||||||
"load-server-state-from-file" and "server-state-file-name"
|
"load-server-state-from-file" and "server-state-file-name"
|
||||||
|
|
||||||
set-dumpable
|
set-dumpable [ on | off | libs ]
|
||||||
|
This option helps choose the core dump behavior in case of process crash.
|
||||||
|
Available options are:
|
||||||
|
|
||||||
|
- on this enables core dumping at the process level if it was
|
||||||
|
previously disabled.
|
||||||
|
|
||||||
|
- off this disables a previously enabled core dumping.
|
||||||
|
|
||||||
|
- libs this enables core dumping with an embedded copy of the binaries and
|
||||||
|
libraries that are required for debugging. This may be requested by
|
||||||
|
developers. In this case haproxy will try to load the libraries it
|
||||||
|
depends on into memory and keep them preciously. If the process
|
||||||
|
crashes, they will be dumped into the core so there is no need for
|
||||||
|
retrieving them from the file system anymore and no risk that they
|
||||||
|
do not match the core. This takes a few megabytes to a few tens of
|
||||||
|
megabytes of additional RAM, so it is better not to use it on small
|
||||||
|
systems.
|
||||||
|
|
||||||
This option is better left disabled by default and enabled only upon a
|
This option is better left disabled by default and enabled only upon a
|
||||||
developer's request. If it has been enabled, it may still be forcibly
|
developer's request. By default it is disabled. Without argument, it defaults
|
||||||
disabled by prefixing it with the "no" keyword. It has no impact on
|
to "on". If it has been enabled, it may still be forcibly disabled by prefixing
|
||||||
|
it with the "no" keyword or by setting it to "off". It has no impact on
|
||||||
performance nor stability but will try hard to re-enable core dumps that were
|
performance nor stability but will try hard to re-enable core dumps that were
|
||||||
possibly disabled by file size limitations (ulimit -f), core size limitations
|
possibly disabled by file size limitations (ulimit -f), core size limitations
|
||||||
(ulimit -c), or "dumpability" of a process after changing its UID/GID (such
|
(ulimit -c), or "dumpability" of a process after changing its UID/GID (such
|
||||||
|
|
@ -3604,6 +3626,11 @@ ssl-skip-self-issued-ca
|
||||||
certificates. It's useless for BoringSSL, .issuer is ignored because ocsp
|
certificates. It's useless for BoringSSL, .issuer is ignored because ocsp
|
||||||
bits does not need it. Requires at least OpenSSL 1.0.2.
|
bits does not need it. Requires at least OpenSSL 1.0.2.
|
||||||
|
|
||||||
|
stats calculate-max-counters [on|off]
|
||||||
|
Activates or deactivates the calculation of stats max counters. If you
|
||||||
|
don't need them, deactivating them may increase performances a bit.
|
||||||
|
The default is on.
|
||||||
|
|
||||||
stats maxconn <connections>
|
stats maxconn <connections>
|
||||||
By default, the stats socket is limited to 10 concurrent connections. It is
|
By default, the stats socket is limited to 10 concurrent connections. It is
|
||||||
possible to change this value with "stats maxconn".
|
possible to change this value with "stats maxconn".
|
||||||
|
|
@ -4138,8 +4165,11 @@ tune.bufsize.small <size>
|
||||||
If however a small buffer is not sufficient, a reallocation is automatically
|
If however a small buffer is not sufficient, a reallocation is automatically
|
||||||
done to switch to a standard size buffer.
|
done to switch to a standard size buffer.
|
||||||
|
|
||||||
For the moment, it is used only by HTTP/3 protocol to emit the response
|
For the moment, it is automatically used only by HTTP/3 protocol to emit the
|
||||||
headers.
|
response headers. Otherwise, small buffers support can be enabled for
|
||||||
|
specific proxies via the "use-small-buffers" option.
|
||||||
|
|
||||||
|
See also: option use-small-buffers
|
||||||
|
|
||||||
tune.comp.maxlevel <number>
|
tune.comp.maxlevel <number>
|
||||||
Sets the maximum compression level. The compression level affects CPU
|
Sets the maximum compression level. The compression level affects CPU
|
||||||
|
|
@ -4344,6 +4374,13 @@ tune.h2.be.max-concurrent-streams <number>
|
||||||
case). It is highly recommended not to increase this value; some might find
|
case). It is highly recommended not to increase this value; some might find
|
||||||
it optimal to run at low values (1..5 typically).
|
it optimal to run at low values (1..5 typically).
|
||||||
|
|
||||||
|
tune.h2.be.max-frames-at-once <number>
|
||||||
|
Sets the maximum number of HTTP/2 incoming frames that will be processed at
|
||||||
|
once on a backend connection. It can be useful to set this to a low value
|
||||||
|
(a few tens to a few hundreds) when dealing with very large buffers in order
|
||||||
|
to maintain a low latency and a better fairness between multiple connections.
|
||||||
|
The default value is zero, which means that no limitation is enforced.
|
||||||
|
|
||||||
tune.h2.be.rxbuf <size>
|
tune.h2.be.rxbuf <size>
|
||||||
Sets the HTTP/2 receive buffer size for outgoing connections, in bytes. This
|
Sets the HTTP/2 receive buffer size for outgoing connections, in bytes. This
|
||||||
size will be rounded up to the next multiple of tune.bufsize and will be
|
size will be rounded up to the next multiple of tune.bufsize and will be
|
||||||
|
|
@ -4394,7 +4431,7 @@ tune.h2.fe.initial-window-size <number>
|
||||||
|
|
||||||
See also: tune.h2.initial-window-size.
|
See also: tune.h2.initial-window-size.
|
||||||
|
|
||||||
tune.h2.fe.max-concurrent-streams <number>
|
tune.h2.fe.max-concurrent-streams <number> [args...]
|
||||||
Sets the HTTP/2 maximum number of concurrent streams per incoming connection
|
Sets the HTTP/2 maximum number of concurrent streams per incoming connection
|
||||||
(i.e. the number of outstanding requests on a single connection from a
|
(i.e. the number of outstanding requests on a single connection from a
|
||||||
client). When not set, the default set by tune.h2.max-concurrent-streams
|
client). When not set, the default set by tune.h2.max-concurrent-streams
|
||||||
|
|
@ -4402,7 +4439,56 @@ tune.h2.fe.max-concurrent-streams <number>
|
||||||
the page load time for complex sites with lots of small objects over high
|
the page load time for complex sites with lots of small objects over high
|
||||||
latency networks but can also result in using more memory by allowing a
|
latency networks but can also result in using more memory by allowing a
|
||||||
client to allocate more resources at once. The default value of 100 is
|
client to allocate more resources at once. The default value of 100 is
|
||||||
generally good and it is recommended not to change this value.
|
generally good and it is recommended not to change this value. A larger
|
||||||
|
concurrency also has an impact on the processing load and latency when
|
||||||
|
dealing with large numbers of connections which are themselves using many
|
||||||
|
streams, and it may lower the barrier to denial of service attacks. The
|
||||||
|
command supports the following optional arguments after the number:
|
||||||
|
|
||||||
|
- rq-load { <number> | auto | ignore }:
|
||||||
|
The optional argument "rq-load" permits to dynamically adjust the
|
||||||
|
advertised concurrency based on the executing thread's run-queue load:
|
||||||
|
as long as the thread's load remains below the indicated threshold, the
|
||||||
|
configured streams limit will be advertised. When the thread's load
|
||||||
|
increases beyond the configured limit, the advertised streams limit will be
|
||||||
|
decreased proportionally to the square of the excess ratio. Target load
|
||||||
|
levels between 50 and 100 generally show very good moderation under heavy
|
||||||
|
loads. Alternately, instead of specifying an explicit number, the keyword
|
||||||
|
accepts "ignore", which is the default and means that the thread's
|
||||||
|
run-queue load will not be considered to moderate the advertised streams
|
||||||
|
limit, and "auto", which sets the limit to the "tune.runqueue-depth"
|
||||||
|
value, which generally provides good results without having to tweak
|
||||||
|
the configuration any further.
|
||||||
|
|
||||||
|
- min <number>:
|
||||||
|
This sets the minimum advertised concurrency level when rq-load is used,
|
||||||
|
even if this results in a higher load than the configured target. This
|
||||||
|
allows to maintain a good level of interactivity on a site under very
|
||||||
|
heavy load. The minimum and default value is 1, but values between 5
|
||||||
|
and 15 can improve user experience.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
tune.h2.fe.max-concurrent-streams 100 rq-load auto min 15
|
||||||
|
|
||||||
|
tune.h2.fe.max-frames-at-once <number>
|
||||||
|
Sets the maximum number of HTTP/2 incoming frames that will be processed at
|
||||||
|
once on a frontend connection. It can be useful to set this to a low value
|
||||||
|
(a few tens to a few hundreds) when dealing with very large buffers in order
|
||||||
|
to maintain a low latency and a better fairness between multiple connections.
|
||||||
|
The default value is zero, which means that no limitation is enforced.
|
||||||
|
|
||||||
|
tune.h2.fe.max-rst-at-once <number>
|
||||||
|
Sets the maximum number of HTTP/2 incoming RST_STREAM that will be processed
|
||||||
|
at once on a frontend connection. Once the specified number of RST_STREAM
|
||||||
|
frames are received, the connection handler will be placed in a low priority
|
||||||
|
queue and be processed after all other tasks. It can be useful to set this to
|
||||||
|
a very low value (1 or a few units) to significantly reduce the impacts of
|
||||||
|
RST_STREAM floods. RST_STREAM do happen when a user clicks on the Stop button
|
||||||
|
in their browser, but the few extra milliseconds caused by this requeuing are
|
||||||
|
generally unnoticeable, however they are generally effective at significantly
|
||||||
|
lowering the load caused from such floods. The default value is zero, which
|
||||||
|
means that no limitation is enforced.
|
||||||
|
|
||||||
tune.h2.fe.max-total-streams <number>
|
tune.h2.fe.max-total-streams <number>
|
||||||
Sets the HTTP/2 maximum number of total streams processed per incoming
|
Sets the HTTP/2 maximum number of total streams processed per incoming
|
||||||
|
|
@ -4478,6 +4564,16 @@ tune.h2.initial-window-size <number>
|
||||||
specific settings tune.h2.fe.initial-window-size and
|
specific settings tune.h2.fe.initial-window-size and
|
||||||
tune.h2.be.initial-window-size.
|
tune.h2.be.initial-window-size.
|
||||||
|
|
||||||
|
tune.h2.log-errors { none | connection | stream }
|
||||||
|
Sets the level of errors in the H2 demultiplexer that will generate a log.
|
||||||
|
The default is "stream", which means that any decoding error encountered in
|
||||||
|
the demultiplexer will lead to the emission of a log. The "connection" value
|
||||||
|
indicates that only logs that result in invalidating the connection will
|
||||||
|
produce a log. Finally, "none" indicates that no decoding error will produce
|
||||||
|
any log. It is recommended to set at least "connection" in order to detect
|
||||||
|
protocol anomalies, even if this means temporarily switching to "none" during
|
||||||
|
difficult periods.
|
||||||
|
|
||||||
tune.h2.max-concurrent-streams <number>
|
tune.h2.max-concurrent-streams <number>
|
||||||
Sets the default HTTP/2 maximum number of concurrent streams per connection
|
Sets the default HTTP/2 maximum number of concurrent streams per connection
|
||||||
(i.e. the number of outstanding requests on a single connection). This value
|
(i.e. the number of outstanding requests on a single connection). This value
|
||||||
|
|
@ -4540,22 +4636,22 @@ tune.http.maxhdr <number>
|
||||||
protocols. This limit is large enough but not documented on purpose. The same
|
protocols. This limit is large enough but not documented on purpose. The same
|
||||||
limit is applied on the first steps of the decoding for the same reason.
|
limit is applied on the first steps of the decoding for the same reason.
|
||||||
|
|
||||||
tune.idle-pool.shared { on | off }
|
tune.idle-pool.shared { auto | on | off }
|
||||||
Enables ('on') or disables ('off') sharing of idle connection pools between
|
Controls sharing idle connection pools between threads for a same server.
|
||||||
threads for a same server. The default is to share them between threads in
|
It can be enabled for all threads in a same thread group ('on'), enabled for
|
||||||
order to minimize the number of persistent connections to a server, and to
|
all threads ('full') or disabled ('off'). The default is to share them
|
||||||
optimize the connection reuse rate. But to help with debugging or when
|
between threads in the same thread group ('on'), in order to minimize the
|
||||||
|
number of persistent connections to a server, and to optimize the connection
|
||||||
|
reuse rate. Sharing with threads from other thread groups can have a
|
||||||
|
performance impact, and is not enabled by default, but can be useful if
|
||||||
|
maximizing connection reuse is a priority. To help with debugging or when
|
||||||
suspecting a bug in HAProxy around connection reuse, it can be convenient to
|
suspecting a bug in HAProxy around connection reuse, it can be convenient to
|
||||||
forcefully disable this idle pool sharing between multiple threads, and force
|
forcefully disable this idle pool sharing between multiple threads,
|
||||||
this option to "off". The default is on. It is strongly recommended against
|
and force this option to "off". It is strongly recommended against disabling
|
||||||
disabling this option without setting a conservative value on "pool-low-conn"
|
this option without setting a conservative value on "pool-low-conn" for all
|
||||||
for all servers relying on connection reuse to achieve a high performance
|
servers relying on connection reuse to achieve a high performance level,
|
||||||
level, otherwise connections might be closed very often as the thread count
|
otherwise connections might be closed very often as the thread count
|
||||||
increases. Note that in any case, connections are only shared between threads
|
increases.
|
||||||
of the same thread group. This means that systems with many NUMA nodes may
|
|
||||||
show slightly more persistent connections while machines with unified caches
|
|
||||||
and many CPU cores per node may experience higher CPU usage. In the latter
|
|
||||||
case, the "max-thread-per-group" tunable may be used to improve the behavior.
|
|
||||||
|
|
||||||
tune.idletimer <timeout>
|
tune.idletimer <timeout>
|
||||||
Sets the duration after which HAProxy will consider that an empty buffer is
|
Sets the duration after which HAProxy will consider that an empty buffer is
|
||||||
|
|
@ -5491,6 +5587,9 @@ tune.takeover-other-tg-connections <value>
|
||||||
connections.
|
connections.
|
||||||
Note that using connections from other thread groups can occur performance
|
Note that using connections from other thread groups can occur performance
|
||||||
penalties, so it should not be used unless really needed.
|
penalties, so it should not be used unless really needed.
|
||||||
|
Note that this behavior is now controlled by tune.idle-pool.shared, and
|
||||||
|
this keyword is just there for compatibility with older configurations, and
|
||||||
|
will be deprecated.
|
||||||
|
|
||||||
tune.vars.global-max-size <size>
|
tune.vars.global-max-size <size>
|
||||||
tune.vars.proc-max-size <size>
|
tune.vars.proc-max-size <size>
|
||||||
|
|
@ -5878,6 +5977,8 @@ errorloc302 X X X X
|
||||||
-- keyword -------------------------- defaults - frontend - listen -- backend -
|
-- keyword -------------------------- defaults - frontend - listen -- backend -
|
||||||
errorloc303 X X X X
|
errorloc303 X X X X
|
||||||
error-log-format X X X -
|
error-log-format X X X -
|
||||||
|
external-check command X - X X
|
||||||
|
external-check path X - X X
|
||||||
force-persist - - X X
|
force-persist - - X X
|
||||||
force-be-switch - X X -
|
force-be-switch - X X -
|
||||||
filter - X X X
|
filter - X X X
|
||||||
|
|
@ -5923,6 +6024,7 @@ option disable-h2-upgrade (*) X X X -
|
||||||
option dontlog-normal (*) X X X -
|
option dontlog-normal (*) X X X -
|
||||||
option dontlognull (*) X X X -
|
option dontlognull (*) X X X -
|
||||||
-- keyword -------------------------- defaults - frontend - listen -- backend -
|
-- keyword -------------------------- defaults - frontend - listen -- backend -
|
||||||
|
option external-check X - X X
|
||||||
option forwardfor X X X X
|
option forwardfor X X X X
|
||||||
option forwarded (*) X - X X
|
option forwarded (*) X - X X
|
||||||
option h1-case-adjust-bogus-client (*) X X X -
|
option h1-case-adjust-bogus-client (*) X X X -
|
||||||
|
|
@ -5941,9 +6043,9 @@ option httpchk X - X X
|
||||||
option httpclose (*) X X X X
|
option httpclose (*) X X X X
|
||||||
option httplog X X X -
|
option httplog X X X -
|
||||||
option httpslog X X X -
|
option httpslog X X X -
|
||||||
|
option idle-close-on-response (*) X X X -
|
||||||
option independent-streams (*) X X X X
|
option independent-streams (*) X X X X
|
||||||
option ldap-check X - X X
|
option ldap-check X - X X
|
||||||
option external-check X - X X
|
|
||||||
option log-health-checks (*) X - X X
|
option log-health-checks (*) X - X X
|
||||||
option log-separate-errors (*) X X X -
|
option log-separate-errors (*) X X X -
|
||||||
option logasap (*) X X X -
|
option logasap (*) X X X -
|
||||||
|
|
@ -5970,9 +6072,7 @@ option tcp-smart-connect (*) X - X X
|
||||||
option tcpka X X X X
|
option tcpka X X X X
|
||||||
option tcplog X X X -
|
option tcplog X X X -
|
||||||
option transparent (deprecated) (*) X - X X
|
option transparent (deprecated) (*) X - X X
|
||||||
option idle-close-on-response (*) X X X -
|
option use-small-buffers (*) X - X X
|
||||||
external-check command X - X X
|
|
||||||
external-check path X - X X
|
|
||||||
persist rdp-cookie X - X X
|
persist rdp-cookie X - X X
|
||||||
quic-initial X (!) X X -
|
quic-initial X (!) X X -
|
||||||
rate-limit sessions X X X -
|
rate-limit sessions X X X -
|
||||||
|
|
@ -6920,12 +7020,16 @@ compression offload
|
||||||
|
|
||||||
See also : "compression type", "compression algo", "compression direction"
|
See also : "compression type", "compression algo", "compression direction"
|
||||||
|
|
||||||
compression direction <direction>
|
compression direction <direction> (deprecated)
|
||||||
Makes haproxy able to compress both requests and responses.
|
Makes haproxy able to compress both requests and responses.
|
||||||
Valid values are "request", to compress only requests, "response", to
|
Valid values are "request", to compress only requests, "response", to
|
||||||
compress only responses, or "both", when you want to compress both.
|
compress only responses, or "both", when you want to compress both.
|
||||||
The default value is "response".
|
The default value is "response".
|
||||||
|
|
||||||
|
This directive is only relevant when legacy "filter compression" was
|
||||||
|
enabled, as with explicit comp-req and comp-res filters compression
|
||||||
|
direction is redundant.
|
||||||
|
|
||||||
May be used in the following contexts: http
|
May be used in the following contexts: http
|
||||||
|
|
||||||
See also : "compression type", "compression algo", "compression offload"
|
See also : "compression type", "compression algo", "compression offload"
|
||||||
|
|
@ -7631,6 +7735,96 @@ force-persist { if | unless } <condition>
|
||||||
and section 7 about ACL usage.
|
and section 7 about ACL usage.
|
||||||
|
|
||||||
|
|
||||||
|
external-check command <command>
|
||||||
|
Executable to run when performing an external-check
|
||||||
|
|
||||||
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
|
yes | no | yes | yes
|
||||||
|
|
||||||
|
Arguments :
|
||||||
|
<command> is the external command to run
|
||||||
|
|
||||||
|
The arguments passed to the to the command are:
|
||||||
|
|
||||||
|
<proxy_address> <proxy_port> <server_address> <server_port>
|
||||||
|
|
||||||
|
The <proxy_address> and <proxy_port> are derived from the first listener
|
||||||
|
that is either IPv4, IPv6 or a UNIX socket. In the case of a UNIX socket
|
||||||
|
listener the proxy_address will be the path of the socket and the
|
||||||
|
<proxy_port> will be the string "NOT_USED". In a backend section, it's not
|
||||||
|
possible to determine a listener, and both <proxy_address> and <proxy_port>
|
||||||
|
will have the string value "NOT_USED".
|
||||||
|
|
||||||
|
Some values are also provided through environment variables.
|
||||||
|
|
||||||
|
Environment variables :
|
||||||
|
HAPROXY_PROXY_ADDR The first bind address if available (or empty if not
|
||||||
|
applicable, for example in a "backend" section).
|
||||||
|
|
||||||
|
HAPROXY_PROXY_ID The backend id.
|
||||||
|
|
||||||
|
HAPROXY_PROXY_NAME The backend name.
|
||||||
|
|
||||||
|
HAPROXY_PROXY_PORT The first bind port if available (or empty if not
|
||||||
|
applicable, for example in a "backend" section or
|
||||||
|
for a UNIX socket).
|
||||||
|
|
||||||
|
HAPROXY_SERVER_ADDR The server address.
|
||||||
|
|
||||||
|
HAPROXY_SERVER_CURCONN The current number of connections on the server.
|
||||||
|
|
||||||
|
HAPROXY_SERVER_ID The server id.
|
||||||
|
|
||||||
|
HAPROXY_SERVER_MAXCONN The server max connections.
|
||||||
|
|
||||||
|
HAPROXY_SERVER_NAME The server name.
|
||||||
|
|
||||||
|
HAPROXY_SERVER_PORT The server port if available (or empty for a UNIX
|
||||||
|
socket).
|
||||||
|
|
||||||
|
HAPROXY_SERVER_SSL "0" when SSL is not used, "1" when it is used
|
||||||
|
|
||||||
|
HAPROXY_SERVER_PROTO The protocol used by this server, which can be one
|
||||||
|
of "cli" (the haproxy CLI), "syslog" (syslog TCP
|
||||||
|
server), "peers" (peers TCP server), "h1" (HTTP/1.x
|
||||||
|
server), "h2" (HTTP/2 server), or "tcp" (any other
|
||||||
|
TCP server).
|
||||||
|
|
||||||
|
PATH The PATH environment variable used when executing
|
||||||
|
the command may be set using "external-check path".
|
||||||
|
|
||||||
|
If the command executed and exits with a zero status then the check is
|
||||||
|
considered to have passed, otherwise the check is considered to have
|
||||||
|
failed.
|
||||||
|
|
||||||
|
Example :
|
||||||
|
external-check command /bin/true
|
||||||
|
|
||||||
|
See also : "external-check", "option external-check", "external-check path"
|
||||||
|
|
||||||
|
|
||||||
|
external-check path <path>
|
||||||
|
The value of the PATH environment variable used when running an external-check
|
||||||
|
|
||||||
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
|
yes | no | yes | yes
|
||||||
|
|
||||||
|
Arguments :
|
||||||
|
<path> is the path used when executing external command to run
|
||||||
|
|
||||||
|
The default path is "".
|
||||||
|
|
||||||
|
Example :
|
||||||
|
external-check path "/usr/bin:/bin"
|
||||||
|
|
||||||
|
See also : "external-check", "option external-check",
|
||||||
|
"external-check command"
|
||||||
|
|
||||||
|
|
||||||
force-be-switch { if | unless } <condition>
|
force-be-switch { if | unless } <condition>
|
||||||
Allow content switching to select a backend instance even if it is disabled
|
Allow content switching to select a backend instance even if it is disabled
|
||||||
or unpublished. This rule can be used by admins to test traffic to services
|
or unpublished. This rule can be used by admins to test traffic to services
|
||||||
|
|
@ -8135,6 +8329,11 @@ http-check expect [min-recv <int>] [comment <msg>]
|
||||||
occurred during the expect rule evaluation. <fmt> is a
|
occurred during the expect rule evaluation. <fmt> is a
|
||||||
Custom log format string (see section 8.2.6).
|
Custom log format string (see section 8.2.6).
|
||||||
|
|
||||||
|
status-code <expr> is optional and can be used to set the check status code
|
||||||
|
reported in logs, on success or on error. <expr> is a
|
||||||
|
standard HAProxy expression formed by a sample-fetch
|
||||||
|
followed by some converters.
|
||||||
|
|
||||||
<match> is a keyword indicating how to look for a specific pattern in the
|
<match> is a keyword indicating how to look for a specific pattern in the
|
||||||
response. The keyword may be one of "status", "rstatus", "hdr",
|
response. The keyword may be one of "status", "rstatus", "hdr",
|
||||||
"fhdr", "string", or "rstring". The keyword may be preceded by an
|
"fhdr", "string", or "rstring". The keyword may be preceded by an
|
||||||
|
|
@ -8244,7 +8443,7 @@ http-check expect [min-recv <int>] [comment <msg>]
|
||||||
http-check expect status 200,201,300-310
|
http-check expect status 200,201,300-310
|
||||||
|
|
||||||
# be sure a sessid coookie is set
|
# be sure a sessid coookie is set
|
||||||
http-check expect header name "set-cookie" value -m beg "sessid="
|
http-check expect hdr name "set-cookie" value -m beg "sessid="
|
||||||
|
|
||||||
# consider SQL errors as errors
|
# consider SQL errors as errors
|
||||||
http-check expect ! string SQL\ Error
|
http-check expect ! string SQL\ Error
|
||||||
|
|
@ -9852,6 +10051,24 @@ no option dontlognull
|
||||||
See also : "log", "http-ignore-probes", "monitor-uri", and
|
See also : "log", "http-ignore-probes", "monitor-uri", and
|
||||||
section 8 about logging.
|
section 8 about logging.
|
||||||
|
|
||||||
|
|
||||||
|
option external-check
|
||||||
|
Use external processes for server health checks
|
||||||
|
|
||||||
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
|
yes | no | yes | yes
|
||||||
|
|
||||||
|
It is possible to test the health of a server using an external command.
|
||||||
|
This is achieved by running the executable set using "external-check
|
||||||
|
command".
|
||||||
|
|
||||||
|
Requires the "external-check" global to be set.
|
||||||
|
|
||||||
|
See also : "external-check", "external-check command", "external-check path"
|
||||||
|
|
||||||
|
|
||||||
option forwarded [ proto ]
|
option forwarded [ proto ]
|
||||||
[ host | host-expr <host_expr> ]
|
[ host | host-expr <host_expr> ]
|
||||||
[ by | by-expr <by_expr> ] [ by_port | by_port-expr <by_port_expr>]
|
[ by | by-expr <by_expr> ] [ by_port | by_port-expr <by_port_expr>]
|
||||||
|
|
@ -10642,6 +10859,39 @@ option httpslog
|
||||||
See also : section 8 about logging.
|
See also : section 8 about logging.
|
||||||
|
|
||||||
|
|
||||||
|
option idle-close-on-response
|
||||||
|
no option idle-close-on-response
|
||||||
|
Avoid closing idle frontend connections if a soft stop is in progress
|
||||||
|
|
||||||
|
May be used in the following contexts: http
|
||||||
|
|
||||||
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
|
yes | yes | yes | no
|
||||||
|
|
||||||
|
Arguments : none
|
||||||
|
|
||||||
|
By default, idle connections will be closed during a soft stop. In some
|
||||||
|
environments, a client talking to the proxy may have prepared some idle
|
||||||
|
connections in order to send requests later. If there is no proper retry on
|
||||||
|
write errors, this can result in errors while haproxy is reloading. Even
|
||||||
|
though a proper implementation should retry on connection/write errors, this
|
||||||
|
option was introduced to support backwards compatibility with haproxy prior
|
||||||
|
to version 2.4. Indeed before v2.4, haproxy used to wait for a last request
|
||||||
|
and response to add a "connection: close" header before closing, thus
|
||||||
|
notifying the client that the connection would not be reusable.
|
||||||
|
|
||||||
|
In a real life example, this behavior was seen in AWS using the ALB in front
|
||||||
|
of a haproxy. The end result was ALB sending 502 during haproxy reloads.
|
||||||
|
|
||||||
|
Users are warned that using this option may increase the number of old
|
||||||
|
processes if connections remain idle for too long. Adjusting the client
|
||||||
|
timeouts and/or the "hard-stop-after" parameter accordingly might be
|
||||||
|
needed in case of frequent reloads.
|
||||||
|
|
||||||
|
See also: "timeout client", "timeout client-fin", "timeout http-request",
|
||||||
|
"hard-stop-after"
|
||||||
|
|
||||||
|
|
||||||
option independent-streams
|
option independent-streams
|
||||||
no option independent-streams
|
no option independent-streams
|
||||||
Enable or disable independent timeout processing for both directions
|
Enable or disable independent timeout processing for both directions
|
||||||
|
|
@ -10706,56 +10956,6 @@ option ldap-check
|
||||||
See also : "option httpchk"
|
See also : "option httpchk"
|
||||||
|
|
||||||
|
|
||||||
option external-check
|
|
||||||
Use external processes for server health checks
|
|
||||||
|
|
||||||
May be used in the following contexts: tcp, http, log
|
|
||||||
|
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
|
||||||
yes | no | yes | yes
|
|
||||||
|
|
||||||
It is possible to test the health of a server using an external command.
|
|
||||||
This is achieved by running the executable set using "external-check
|
|
||||||
command".
|
|
||||||
|
|
||||||
Requires the "external-check" global to be set.
|
|
||||||
|
|
||||||
See also : "external-check", "external-check command", "external-check path"
|
|
||||||
|
|
||||||
|
|
||||||
option idle-close-on-response
|
|
||||||
no option idle-close-on-response
|
|
||||||
Avoid closing idle frontend connections if a soft stop is in progress
|
|
||||||
|
|
||||||
May be used in the following contexts: http
|
|
||||||
|
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
|
||||||
yes | yes | yes | no
|
|
||||||
|
|
||||||
Arguments : none
|
|
||||||
|
|
||||||
By default, idle connections will be closed during a soft stop. In some
|
|
||||||
environments, a client talking to the proxy may have prepared some idle
|
|
||||||
connections in order to send requests later. If there is no proper retry on
|
|
||||||
write errors, this can result in errors while haproxy is reloading. Even
|
|
||||||
though a proper implementation should retry on connection/write errors, this
|
|
||||||
option was introduced to support backwards compatibility with haproxy prior
|
|
||||||
to version 2.4. Indeed before v2.4, haproxy used to wait for a last request
|
|
||||||
and response to add a "connection: close" header before closing, thus
|
|
||||||
notifying the client that the connection would not be reusable.
|
|
||||||
|
|
||||||
In a real life example, this behavior was seen in AWS using the ALB in front
|
|
||||||
of a haproxy. The end result was ALB sending 502 during haproxy reloads.
|
|
||||||
|
|
||||||
Users are warned that using this option may increase the number of old
|
|
||||||
processes if connections remain idle for too long. Adjusting the client
|
|
||||||
timeouts and/or the "hard-stop-after" parameter accordingly might be
|
|
||||||
needed in case of frequent reloads.
|
|
||||||
|
|
||||||
See also: "timeout client", "timeout client-fin", "timeout http-request",
|
|
||||||
"hard-stop-after"
|
|
||||||
|
|
||||||
|
|
||||||
option log-health-checks
|
option log-health-checks
|
||||||
no option log-health-checks
|
no option log-health-checks
|
||||||
Enable or disable logging of health checks status updates
|
Enable or disable logging of health checks status updates
|
||||||
|
|
@ -11717,95 +11917,35 @@ no option transparent (deprecated)
|
||||||
"transparent" option of the "bind" keyword.
|
"transparent" option of the "bind" keyword.
|
||||||
|
|
||||||
|
|
||||||
external-check command <command>
|
option use-small-buffers [ queue | l7-retries | check ]*
|
||||||
Executable to run when performing an external-check
|
|
||||||
|
|
||||||
May be used in the following contexts: tcp, http, log
|
Enable support for small buffers for the given categories.
|
||||||
|
|
||||||
|
May be used in the following contexts: tcp, http
|
||||||
|
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
yes | no | yes | yes
|
yes | no | yes | yes
|
||||||
|
|
||||||
Arguments :
|
This option can be used to enable the small buffers support at diffent places
|
||||||
<command> is the external command to run
|
to save memory. By default, with no parameter, small buffers are used as far
|
||||||
|
as possible at all possible places. Otherwise, it is possible to limit it to
|
||||||
|
following the places:
|
||||||
|
|
||||||
The arguments passed to the to the command are:
|
- queue: When set, small buffers will be used to store the requests, if
|
||||||
|
small enough, when the connection is queued.
|
||||||
|
- l7-retries: When set, small buffers will be used to save the requests
|
||||||
|
when L7 retries are enabled.
|
||||||
|
- check: When set, small buffers will be used for the health-checks
|
||||||
|
requests.
|
||||||
|
|
||||||
<proxy_address> <proxy_port> <server_address> <server_port>
|
When enabled, small buffers are used, but only if it is possible. Otherwise,
|
||||||
|
when data are too large, a regular buffer is automtically used. The size of
|
||||||
|
small buffers is configurable via the "tune.bufsize.small" global setting.
|
||||||
|
|
||||||
The <proxy_address> and <proxy_port> are derived from the first listener
|
If this option has been enabled in a "defaults" section, it can be disabled
|
||||||
that is either IPv4, IPv6 or a UNIX socket. In the case of a UNIX socket
|
in a specific instance by prepending the "no" keyword before it.
|
||||||
listener the proxy_address will be the path of the socket and the
|
|
||||||
<proxy_port> will be the string "NOT_USED". In a backend section, it's not
|
|
||||||
possible to determine a listener, and both <proxy_address> and <proxy_port>
|
|
||||||
will have the string value "NOT_USED".
|
|
||||||
|
|
||||||
Some values are also provided through environment variables.
|
|
||||||
|
|
||||||
Environment variables :
|
|
||||||
HAPROXY_PROXY_ADDR The first bind address if available (or empty if not
|
|
||||||
applicable, for example in a "backend" section).
|
|
||||||
|
|
||||||
HAPROXY_PROXY_ID The backend id.
|
|
||||||
|
|
||||||
HAPROXY_PROXY_NAME The backend name.
|
|
||||||
|
|
||||||
HAPROXY_PROXY_PORT The first bind port if available (or empty if not
|
|
||||||
applicable, for example in a "backend" section or
|
|
||||||
for a UNIX socket).
|
|
||||||
|
|
||||||
HAPROXY_SERVER_ADDR The server address.
|
|
||||||
|
|
||||||
HAPROXY_SERVER_CURCONN The current number of connections on the server.
|
|
||||||
|
|
||||||
HAPROXY_SERVER_ID The server id.
|
|
||||||
|
|
||||||
HAPROXY_SERVER_MAXCONN The server max connections.
|
|
||||||
|
|
||||||
HAPROXY_SERVER_NAME The server name.
|
|
||||||
|
|
||||||
HAPROXY_SERVER_PORT The server port if available (or empty for a UNIX
|
|
||||||
socket).
|
|
||||||
|
|
||||||
HAPROXY_SERVER_SSL "0" when SSL is not used, "1" when it is used
|
|
||||||
|
|
||||||
HAPROXY_SERVER_PROTO The protocol used by this server, which can be one
|
|
||||||
of "cli" (the haproxy CLI), "syslog" (syslog TCP
|
|
||||||
server), "peers" (peers TCP server), "h1" (HTTP/1.x
|
|
||||||
server), "h2" (HTTP/2 server), or "tcp" (any other
|
|
||||||
TCP server).
|
|
||||||
|
|
||||||
PATH The PATH environment variable used when executing
|
|
||||||
the command may be set using "external-check path".
|
|
||||||
|
|
||||||
If the command executed and exits with a zero status then the check is
|
|
||||||
considered to have passed, otherwise the check is considered to have
|
|
||||||
failed.
|
|
||||||
|
|
||||||
Example :
|
|
||||||
external-check command /bin/true
|
|
||||||
|
|
||||||
See also : "external-check", "option external-check", "external-check path"
|
|
||||||
|
|
||||||
|
|
||||||
external-check path <path>
|
|
||||||
The value of the PATH environment variable used when running an external-check
|
|
||||||
|
|
||||||
May be used in the following contexts: tcp, http, log
|
|
||||||
|
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
|
||||||
yes | no | yes | yes
|
|
||||||
|
|
||||||
Arguments :
|
|
||||||
<path> is the path used when executing external command to run
|
|
||||||
|
|
||||||
The default path is "".
|
|
||||||
|
|
||||||
Example :
|
|
||||||
external-check path "/usr/bin:/bin"
|
|
||||||
|
|
||||||
See also : "external-check", "option external-check",
|
|
||||||
"external-check command"
|
|
||||||
|
|
||||||
|
See also: tune.bufsize.small
|
||||||
|
|
||||||
persist rdp-cookie
|
persist rdp-cookie
|
||||||
persist rdp-cookie(<name>)
|
persist rdp-cookie(<name>)
|
||||||
|
|
@ -13564,13 +13704,6 @@ tcp-check expect [min-recv <int>] [comment <msg>]
|
||||||
does not match, the check will wait for more data. If set to 0,
|
does not match, the check will wait for more data. If set to 0,
|
||||||
the evaluation result is always conclusive.
|
the evaluation result is always conclusive.
|
||||||
|
|
||||||
<match> is a keyword indicating how to look for a specific pattern in the
|
|
||||||
response. The keyword may be one of "string", "rstring", "binary" or
|
|
||||||
"rbinary".
|
|
||||||
The keyword may be preceded by an exclamation mark ("!") to negate
|
|
||||||
the match. Spaces are allowed between the exclamation mark and the
|
|
||||||
keyword. See below for more details on the supported keywords.
|
|
||||||
|
|
||||||
ok-status <st> is optional and can be used to set the check status if
|
ok-status <st> is optional and can be used to set the check status if
|
||||||
the expect rule is successfully evaluated and if it is
|
the expect rule is successfully evaluated and if it is
|
||||||
the last rule in the tcp-check ruleset. "L7OK", "L7OKC",
|
the last rule in the tcp-check ruleset. "L7OK", "L7OKC",
|
||||||
|
|
@ -13618,6 +13751,13 @@ tcp-check expect [min-recv <int>] [comment <msg>]
|
||||||
standard HAProxy expression formed by a sample-fetch
|
standard HAProxy expression formed by a sample-fetch
|
||||||
followed by some converters.
|
followed by some converters.
|
||||||
|
|
||||||
|
<match> is a keyword indicating how to look for a specific pattern in the
|
||||||
|
response. The keyword may be one of "string", "rstring", "binary" or
|
||||||
|
"rbinary".
|
||||||
|
The keyword may be preceded by an exclamation mark ("!") to negate
|
||||||
|
the match. Spaces are allowed between the exclamation mark and the
|
||||||
|
keyword. See below for more details on the supported keywords.
|
||||||
|
|
||||||
<pattern> is the pattern to look for. It may be a string or a regular
|
<pattern> is the pattern to look for. It may be a string or a regular
|
||||||
expression. If the pattern contains spaces, they must be escaped
|
expression. If the pattern contains spaces, they must be escaped
|
||||||
with the usual backslash ('\').
|
with the usual backslash ('\').
|
||||||
|
|
@ -15314,15 +15454,14 @@ disable-l7-retry
|
||||||
reason than a connection failure. This can be useful for example to make
|
reason than a connection failure. This can be useful for example to make
|
||||||
sure POST requests aren't retried on failure.
|
sure POST requests aren't retried on failure.
|
||||||
|
|
||||||
do-log
|
do-log [profile <log_profile>]
|
||||||
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
||||||
X | X | X | X | X | X | X | X
|
X | X | X | X | X | X | X | X
|
||||||
|
|
||||||
This action manually triggers a log emission on the proxy. This means
|
This action manually triggers a log emission on the proxy. This means
|
||||||
log options on the proxy will be considered (including formatting options
|
log options on the proxy will be considered (including formatting options
|
||||||
such as "log-format"), but it will not interfere with the logs automatically
|
such as "log-format"), but it will not interfere with the logs automatically
|
||||||
generated by the proxy during transaction handling. It currently doesn't
|
generated by the proxy during transaction handling.
|
||||||
support any argument, though extensions may appear in future versions.
|
|
||||||
|
|
||||||
Using "log-profile", it is possible to precisely describe how the log should
|
Using "log-profile", it is possible to precisely describe how the log should
|
||||||
be emitted for each of the available contexts where the action may be used.
|
be emitted for each of the available contexts where the action may be used.
|
||||||
|
|
@ -15332,15 +15471,28 @@ do-log
|
||||||
|
|
||||||
Also, they will be properly reported when using "%OG" logformat alias.
|
Also, they will be properly reported when using "%OG" logformat alias.
|
||||||
|
|
||||||
|
Optional "profile" argument may be used to specify the name of a log-profile
|
||||||
|
section that should be used for this do-log action specifically instead of
|
||||||
|
the one associated to the current logger that applies by default.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
log-profile myprof
|
log-profile my-dft-prof
|
||||||
on tcp-req-conn format "Connect: %ci"
|
on tcp-req-conn format "Connect: %ci"
|
||||||
|
|
||||||
|
log-profile my-local-prof
|
||||||
|
on tcp-req-conn format "Local Connect: %ci"
|
||||||
|
|
||||||
frontend myfront
|
frontend myfront
|
||||||
log stdout format rfc5424 profile myprof local0
|
log stdout format rfc5424 profile my-dft-prof local0
|
||||||
log-format "log generated using proxy logformat, from '%OG'"
|
log-format "log generated using proxy logformat, from '%OG'"
|
||||||
tcp-request connection do-log #uses special log-profile format
|
acl local src 127.0.0.1
|
||||||
tcp-request content do-log #uses proxy logformat
|
# on connection use either log-profile from the logger (my-dft-prof) or
|
||||||
|
# explicit my-local-prof if source ip is localhost
|
||||||
|
tcp-request connection do-log if !local
|
||||||
|
tcp-request connection do-log profile my-local-prof if local
|
||||||
|
# on content use proxy logformat, since no override was specified
|
||||||
|
# in my-dft-prof
|
||||||
|
tcp-request content do-log
|
||||||
|
|
||||||
do-resolve(<var>,<resolvers>[,ipv4|ipv6]) <expr>
|
do-resolve(<var>,<resolvers>[,ipv4|ipv6]) <expr>
|
||||||
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
||||||
|
|
@ -21484,7 +21636,8 @@ jwt_decrypt_cert(<cert>)
|
||||||
format (five dot-separated base64-url encoded strings).
|
format (five dot-separated base64-url encoded strings).
|
||||||
|
|
||||||
This converter can be used for tokens that have an algorithm ("alg" field of
|
This converter can be used for tokens that have an algorithm ("alg" field of
|
||||||
the JOSE header) among the following: RSA1_5, RSA-OAEP or RSA-OAEP-256.
|
the JOSE header) among the following: RSA1_5, RSA-OAEP, RSA-OAEP-256,
|
||||||
|
ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW or ECDH-ES+A256KW.
|
||||||
|
|
||||||
The JWE token must be provided base64url-encoded and the output will be
|
The JWE token must be provided base64url-encoded and the output will be
|
||||||
provided "raw". If an error happens during token parsing, signature
|
provided "raw". If an error happens during token parsing, signature
|
||||||
|
|
@ -21500,8 +21653,9 @@ jwt_decrypt_jwk(<jwk>)
|
||||||
Performs a signature validation of a JSON Web Token following the JSON Web
|
Performs a signature validation of a JSON Web Token following the JSON Web
|
||||||
Encryption format (see RFC 7516) given in input and return its content
|
Encryption format (see RFC 7516) given in input and return its content
|
||||||
decrypted thanks to the provided JSON Web Key (RFC7517).
|
decrypted thanks to the provided JSON Web Key (RFC7517).
|
||||||
The <jwk> parameter must be a valid JWK of type 'oct' or 'RSA' ('kty' field
|
The <jwk> parameter must be a valid JWK of type 'oct', 'EC' or 'RSA' ('kty'
|
||||||
of the JSON key) that can be provided either as a string or via a variable.
|
field of the JSON key) that can be provided either as a string or via a
|
||||||
|
variable.
|
||||||
|
|
||||||
The only tokens managed yet are the ones using the Compact Serialization
|
The only tokens managed yet are the ones using the Compact Serialization
|
||||||
format (five dot-separated base64-url encoded strings).
|
format (five dot-separated base64-url encoded strings).
|
||||||
|
|
@ -21509,11 +21663,16 @@ jwt_decrypt_jwk(<jwk>)
|
||||||
This converter can be used to decode token that have a symmetric-type
|
This converter can be used to decode token that have a symmetric-type
|
||||||
algorithm ("alg" field of the JOSE header) among the following: A128KW,
|
algorithm ("alg" field of the JOSE header) among the following: A128KW,
|
||||||
A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW, dir. In this case, we expect
|
A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW, dir. In this case, we expect
|
||||||
the provided JWK to be of the 'oct' type. Please note that the A128KW and
|
the provided JWK to be of the 'oct' type.
|
||||||
A192KW algorithms are not available on AWS-LC and decryption will not work.
|
|
||||||
This converter also manages tokens that have an algorithm ("alg" field of
|
This converter also manages tokens that have an algorithm ("alg" field of the
|
||||||
the JOSE header) among the following: RSA1_5, RSA-OAEP or RSA-OAEP-256. In
|
JOSE header) in the RSA family (RSA1_5, RSA-OAEP or RSA-OAEP-256) when
|
||||||
such a case an 'RSA' type JWK representing a private key must be provided.
|
provided an 'RSA' JWK, or in the ECDH family (ECDH-ES, ECDH-ES+A128KW,
|
||||||
|
ECDH-ES+A192KW or ECDH-ES+A256KW) when provided an 'EC' JWK.
|
||||||
|
|
||||||
|
Please note that the A128KW and A192KW algorithms are not available on AWS-LC
|
||||||
|
so the A128KW, A192KW, ECDH-ES+A128KW and ECDH-ES+A192KW algorithms won't
|
||||||
|
work.
|
||||||
|
|
||||||
The JWE token must be provided base64url-encoded and the output will be
|
The JWE token must be provided base64url-encoded and the output will be
|
||||||
provided "raw". If an error happens during token parsing, signature
|
provided "raw". If an error happens during token parsing, signature
|
||||||
|
|
@ -21527,7 +21686,7 @@ jwt_decrypt_jwk(<jwk>)
|
||||||
# Get a JWT from the authorization header, put its decrypted content in an
|
# Get a JWT from the authorization header, put its decrypted content in an
|
||||||
# HTTP header
|
# HTTP header
|
||||||
http-request set-var(txn.bearer) http_auth_bearer
|
http-request set-var(txn.bearer) http_auth_bearer
|
||||||
http-request set-header X-Decrypted %[var(txn.bearer),jwt_decrypt_secret(\'{\"kty\":\"oct\",\"k\":\"wAsgsg\"}\')
|
http-request set-header X-Decrypted %[var(txn.bearer),jwt_decrypt_jwk(\'{\"kty\":\"oct\",\"k\":\"wAsgsg\"}\')
|
||||||
|
|
||||||
# or via a variable
|
# or via a variable
|
||||||
http-request set-var(txn.bearer) http_auth_bearer
|
http-request set-var(txn.bearer) http_auth_bearer
|
||||||
|
|
@ -26897,9 +27056,10 @@ capture.req.uri : string
|
||||||
allocated.
|
allocated.
|
||||||
|
|
||||||
capture.req.ver : string
|
capture.req.ver : string
|
||||||
This extracts the request's HTTP version and returns either "HTTP/1.0" or
|
This extracts the request's HTTP version and returns it with the format
|
||||||
"HTTP/1.1". Unlike "req.ver", it can be used in both request, response, and
|
"HTTP/<major>.<minor>". It can be used in both request, response, and logs
|
||||||
logs because it relies on a persistent flag.
|
because it relies on a persistent information. If the request version is not
|
||||||
|
valid, this sample fetch fails.
|
||||||
|
|
||||||
capture.res.hdr(<idx>) : string
|
capture.res.hdr(<idx>) : string
|
||||||
This extracts the content of the header captured by the "capture response
|
This extracts the content of the header captured by the "capture response
|
||||||
|
|
@ -26908,9 +27068,10 @@ capture.res.hdr(<idx>) : string
|
||||||
See also: "capture response header"
|
See also: "capture response header"
|
||||||
|
|
||||||
capture.res.ver : string
|
capture.res.ver : string
|
||||||
This extracts the response's HTTP version and returns either "HTTP/1.0" or
|
This extracts the response's HTTP version and returns it with the format
|
||||||
"HTTP/1.1". Unlike "res.ver", it can be used in logs because it relies on a
|
"HTTP/<major>.<minor>". It can be used in logs because it relies on a
|
||||||
persistent flag.
|
persistent information. If the response version is not valid, this sample
|
||||||
|
fetch fails.
|
||||||
|
|
||||||
cookie([<name>]) : string (deprecated)
|
cookie([<name>]) : string (deprecated)
|
||||||
This extracts the last occurrence of the cookie name <name> on a "Cookie"
|
This extracts the last occurrence of the cookie name <name> on a "Cookie"
|
||||||
|
|
@ -27261,16 +27422,14 @@ req.timer.tq : integer
|
||||||
|
|
||||||
req.ver : string
|
req.ver : string
|
||||||
req_ver : string (deprecated)
|
req_ver : string (deprecated)
|
||||||
Returns the version string from the HTTP request, for example "1.1". This can
|
Returns the version string from the HTTP request, with the format
|
||||||
be useful for ACL. For logs use the "%HV" logformat alias. Some predefined
|
"<major>.<minor>". This can be useful for ACL. Some predefined ACL already
|
||||||
ACL already check for versions 1.0 and 1.1.
|
check for common versions. It can be used in both request, response, and
|
||||||
|
logs because it relies on a persistent information. If the request version is
|
||||||
|
not valid, this sample fetch fails.
|
||||||
|
|
||||||
Common values are "1.0", "1.1", "2.0" or "3.0".
|
Common values are "1.0", "1.1", "2.0" or "3.0".
|
||||||
|
|
||||||
In the case of http/2 and http/3, the value is not extracted from the HTTP
|
|
||||||
version in the request line but is determined by the negotiated protocol
|
|
||||||
version.
|
|
||||||
|
|
||||||
ACL derivatives :
|
ACL derivatives :
|
||||||
req.ver : exact string match
|
req.ver : exact string match
|
||||||
|
|
||||||
|
|
@ -27474,8 +27633,9 @@ res.timer.hdr : integer
|
||||||
|
|
||||||
res.ver : string
|
res.ver : string
|
||||||
resp_ver : string (deprecated)
|
resp_ver : string (deprecated)
|
||||||
Returns the version string from the HTTP response, for example "1.1". This
|
Returns the version string from the HTTP response, with the format
|
||||||
can be useful for logs, but is mostly there for ACL.
|
"<major>.<minor>". This can be useful for logs, but is mostly there for
|
||||||
|
ACL. If the response version is not valid, this sample fetch fails.
|
||||||
|
|
||||||
It may be used in tcp-check based expect rules.
|
It may be used in tcp-check based expect rules.
|
||||||
|
|
||||||
|
|
@ -28037,7 +28197,7 @@ Detailed fields description :
|
||||||
limits have been reached. For instance, if actconn is close to 512 when
|
limits have been reached. For instance, if actconn is close to 512 when
|
||||||
multiple connection errors occur, chances are high that the system limits
|
multiple connection errors occur, chances are high that the system limits
|
||||||
the process to use a maximum of 1024 file descriptors and that all of them
|
the process to use a maximum of 1024 file descriptors and that all of them
|
||||||
are used. See section 3 "Global parameters" to find how to tune the system.
|
are used. See section 3 "Global section" to find how to tune the system.
|
||||||
|
|
||||||
- "feconn" is the total number of concurrent connections on the frontend when
|
- "feconn" is the total number of concurrent connections on the frontend when
|
||||||
the session was logged. It is useful to estimate the amount of resource
|
the session was logged. It is useful to estimate the amount of resource
|
||||||
|
|
@ -28277,7 +28437,7 @@ Detailed fields description :
|
||||||
limits have been reached. For instance, if actconn is close to 512 or 1024
|
limits have been reached. For instance, if actconn is close to 512 or 1024
|
||||||
when multiple connection errors occur, chances are high that the system
|
when multiple connection errors occur, chances are high that the system
|
||||||
limits the process to use a maximum of 1024 file descriptors and that all
|
limits the process to use a maximum of 1024 file descriptors and that all
|
||||||
of them are used. See section 3 "Global parameters" to find how to tune the
|
of them are used. See section 3 "Global section" to find how to tune the
|
||||||
system.
|
system.
|
||||||
|
|
||||||
- "feconn" is the total number of concurrent connections on the frontend when
|
- "feconn" is the total number of concurrent connections on the frontend when
|
||||||
|
|
@ -28735,7 +28895,7 @@ Please refer to the table below for currently defined aliases :
|
||||||
| Others |
|
| Others |
|
||||||
+---+------+------------------------------------------------------+---------+
|
+---+------+------------------------------------------------------+---------+
|
||||||
| | %B | bytes_read (from server to client) | numeric |
|
| | %B | bytes_read (from server to client) | numeric |
|
||||||
| | | %[req.bytes_in] | |
|
| | | %[res.bytes_in] | |
|
||||||
+---+------+------------------------------------------------------+---------+
|
+---+------+------------------------------------------------------+---------+
|
||||||
| H | %CC | captured_request_cookie | string |
|
| H | %CC | captured_request_cookie | string |
|
||||||
+---+------+------------------------------------------------------+---------+
|
+---+------+------------------------------------------------------+---------+
|
||||||
|
|
@ -29888,7 +30048,21 @@ a server by adding some latencies in the processing.
|
||||||
9.2. HTTP compression
|
9.2. HTTP compression
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
filter compression
|
filter comp-req
|
||||||
|
|
||||||
|
Enables filter that explicitly tries to compress HTTP requests according to
|
||||||
|
"compression" settings. Implicitly sets "compression direction request".
|
||||||
|
|
||||||
|
filter comp-res
|
||||||
|
|
||||||
|
Enables filter that explicitly tries to compress HTTP responses according to
|
||||||
|
"compression" settings. Implicitly sets "compression direction response"
|
||||||
|
|
||||||
|
filter compression (deprecated)
|
||||||
|
|
||||||
|
Alias for backward compatibility purposes that is functionnally equivalent to
|
||||||
|
enabling both "comp-req" and "comp-res" filter. "compression" keyword must be
|
||||||
|
used to configure appropriate behavior:
|
||||||
|
|
||||||
The HTTP compression has been moved in a filter in HAProxy 1.7. "compression"
|
The HTTP compression has been moved in a filter in HAProxy 1.7. "compression"
|
||||||
keyword must still be used to enable and configure the HTTP compression. And
|
keyword must still be used to enable and configure the HTTP compression. And
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,13 @@ versions. It displays its usage when run without argument or wrong arguments:
|
||||||
-T <line> : multiple option; append <line> to the "traces" section
|
-T <line> : multiple option; append <line> to the "traces" section
|
||||||
-C : dump the configuration and exit
|
-C : dump the configuration and exit
|
||||||
-D : goes daemon
|
-D : goes daemon
|
||||||
|
-b <keysize> : RSA key size in bits (ex: "2048", "4096"...)
|
||||||
|
-c <curves> : ECSDA curves (ex: "P-256", "P-384"...)
|
||||||
-v : shows version
|
-v : shows version
|
||||||
-d : enable the traces for all http protocols
|
-d : enable the traces for all http protocols
|
||||||
|
--quic-bind-opts <opts> : append options to QUIC "bind" lines
|
||||||
|
--tcp-bind-opts <opts> : append options to TCP "bind" lines
|
||||||
|
|
||||||
|
|
||||||
Arguments -G, -F, -T permit to append one or multiple lines at the end of their
|
Arguments -G, -F, -T permit to append one or multiple lines at the end of their
|
||||||
respective sections. A tab character ('\t') is prepended at the beginning of
|
respective sections. A tab character ('\t') is prepended at the beginning of
|
||||||
|
|
|
||||||
|
|
@ -539,10 +539,22 @@ message. These functions are used by HTX analyzers or by multiplexers.
|
||||||
with the first block not removed, or NULL if everything was removed, and
|
with the first block not removed, or NULL if everything was removed, and
|
||||||
the amount of data drained.
|
the amount of data drained.
|
||||||
|
|
||||||
- htx_xfer_blks() transfers HTX blocks from an HTX message to another,
|
- htx_xfer() transfers HTX blocks from an HTX message to another, stopping
|
||||||
stopping after the first block of a specified type is transferred or when
|
when a specific amount of bytes, including meta-data, was copied. If the
|
||||||
a specific amount of bytes, including meta-data, was moved. If the tail
|
tail block is a DATA block, it may be partially copied. All other block
|
||||||
block is a DATA block, it may be partially moved. All other block are
|
are transferred at once. By default, copied blocks are removed from the
|
||||||
|
original HTX message and headers and trailers parts cannot be partially
|
||||||
|
copied. But flags can be set to change the default behavior:
|
||||||
|
|
||||||
|
- HTX_XFER_KEEP_SRC_BLKS: source blocks are not removed
|
||||||
|
- HTX_XFER_PARTIAL_HDRS_COPY: partial headers and trailers
|
||||||
|
part can be xferred
|
||||||
|
- HTX_XFER_HDRS_ONLY: Only the headers part is xferred
|
||||||
|
|
||||||
|
- htx_xfer_blks() [DEPRECATED] transfers HTX blocks from an HTX message to
|
||||||
|
another, stopping after the first block of a specified type is transferred
|
||||||
|
or when a specific amount of bytes, including meta-data, was moved. If the
|
||||||
|
tail block is a DATA block, it may be partially moved. All other block are
|
||||||
transferred at once or kept. This function returns a mixed value, with the
|
transferred at once or kept. This function returns a mixed value, with the
|
||||||
last block moved, or NULL if nothing was moved, and the amount of data
|
last block moved, or NULL if nothing was moved, and the amount of data
|
||||||
transferred. When HEADERS or TRAILERS blocks must be transferred, this
|
transferred. When HEADERS or TRAILERS blocks must be transferred, this
|
||||||
|
|
|
||||||
50
doc/internals/thread-exec-ctx.txt
Normal file
50
doc/internals/thread-exec-ctx.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
2026-03-12 - thread execution context
|
||||||
|
|
||||||
|
Thread execution context (thread_exec_ctx) is a combination of type and pointer
|
||||||
|
that are set in the current running thread at th_ctx->exec_ctx when entering
|
||||||
|
certain processing (tasks, sample fetch functions, actions, CLI keywords etc).
|
||||||
|
They're refined along execution, so that a task such as process_stream could
|
||||||
|
temporarily switch to a converter while evaluating an expression and switch
|
||||||
|
back to process_stream. They are reported in thread dumps and are mixed with
|
||||||
|
caller locations for memory profiling. As such they are intentionally not too
|
||||||
|
precise in order to avoid an explosion of the number of buckets. At the moment,
|
||||||
|
the level of granularity it provides is sufficient to try to narrow a
|
||||||
|
misbehaving origin down to a list of keywords. The context types can currently
|
||||||
|
be:
|
||||||
|
|
||||||
|
- something registered via an initcall, with the initcall's location
|
||||||
|
- something registered via an ha_caller, with the caller's location
|
||||||
|
- an explicit sample fetch / converter / action / CLI keyword list
|
||||||
|
- an explicit function (mainly used for actions without keywords)
|
||||||
|
- a task / tasklet (no distinction is made), using the ->process pointer
|
||||||
|
- a filter (e.g. compression), via flt_conf, reporting name
|
||||||
|
- a mux (via the mux_ops, reporting the name)
|
||||||
|
- an applet (e.g. cache, stats, CLI)
|
||||||
|
|
||||||
|
A macro EXEC_CTX_MAKE(type, pointer) makes a thread_exec_ctx from such
|
||||||
|
values.
|
||||||
|
|
||||||
|
A macro EXEC_CTX_NO_RET(ctx, statement) calls a void statement under the
|
||||||
|
specified context.
|
||||||
|
|
||||||
|
A macro EXEC_CTX_WITH_RET(ctx, expr) calls an expression under the specified
|
||||||
|
context.
|
||||||
|
|
||||||
|
Most locations were modified to directly use these macros on the fly, by
|
||||||
|
retrieving the context from where it was set on the element being evaluated
|
||||||
|
(e.g. an action rule contains the context inherited by the action keyword
|
||||||
|
that was used to create it).
|
||||||
|
|
||||||
|
In tools.c, chunk_append_thread_ctx() tries to decode the given exec_ctx and
|
||||||
|
appends it into the provided buffer. It's used by ha_thread_dump_one() and
|
||||||
|
cli_io_handler_show_activity() for memory profiling. In this latter case,
|
||||||
|
the detected thread_ctx are reported in the output under brackets prefixed
|
||||||
|
with "[via ...]" to distinguish call paths to the same allocators.
|
||||||
|
|
||||||
|
A good way to test if a context is properly reported is to place a bleeding
|
||||||
|
malloc() call into one of the monitored functions, e.g.:
|
||||||
|
|
||||||
|
DISGUISE(malloc(8));
|
||||||
|
|
||||||
|
and issue "show profiling memory" after stressing the function. Its context
|
||||||
|
must appear on the right with the number of calls.
|
||||||
|
|
@ -1740,10 +1740,7 @@ add backend <name> from <defproxy> [mode <mode>] [guid <guid>] [ EXPERIMENTAL ]
|
||||||
|
|
||||||
All named default proxies can be used, given that they validate the same
|
All named default proxies can be used, given that they validate the same
|
||||||
inheritance rules applied during configuration parsing. There is some
|
inheritance rules applied during configuration parsing. There is some
|
||||||
exceptions though, for example when the mode is neither TCP nor HTTP. Another
|
exceptions though, for example when the mode is neither TCP nor HTTP.
|
||||||
exception is that it is not yet possible to use a default proxies which
|
|
||||||
reference custom HTTP errors, for example via the errorfiles or http-rules
|
|
||||||
keywords.
|
|
||||||
|
|
||||||
This command is restricted and can only be issued on sockets configured for
|
This command is restricted and can only be issued on sockets configured for
|
||||||
level "admin". Moreover, this feature is still considered in development so it
|
level "admin". Moreover, this feature is still considered in development so it
|
||||||
|
|
@ -2124,6 +2121,30 @@ del acl <acl> [<key>|#<ref>]
|
||||||
listing the content of the acl. Note that if the reference <acl> is a name and
|
listing the content of the acl. Note that if the reference <acl> is a name and
|
||||||
is shared with a map, the entry will be also deleted in the map.
|
is shared with a map, the entry will be also deleted in the map.
|
||||||
|
|
||||||
|
del backend <name>
|
||||||
|
Removes the backend proxy with the name <name>.
|
||||||
|
|
||||||
|
This operation is only possible for TCP or HTTP proxies. To succeed, the
|
||||||
|
backend instance must have been first unpublished. Also, all of its servers
|
||||||
|
must first be removed (via "del server" CLI). Finally, no stream must still
|
||||||
|
be attached to the backend instance.
|
||||||
|
|
||||||
|
There is additional restrictions which prevent backend removal. First, a
|
||||||
|
backend cannot be removed if it is explicitely referenced by config elements,
|
||||||
|
for example via a use_backend rule or in sample expressions. Some proxies
|
||||||
|
options are also incompatible with runtime deletion. Currently, this is the
|
||||||
|
case when deprecated dispatch or option transparent are used. Also, a backend
|
||||||
|
cannot be removed if there is a stick-table declared in it. Finally, it is
|
||||||
|
impossible for now to remove a backend if QUIC servers were present in it.
|
||||||
|
|
||||||
|
It can be useful to use "wait be-removable" prior to this command to check
|
||||||
|
for the aformentioned requisites. This also provides a methode to wait for
|
||||||
|
the final closure of the streams attached to the target backend.
|
||||||
|
|
||||||
|
This command is restricted and can only be issued on sockets configured for
|
||||||
|
level "admin". Moreover, this feature is still considered in development so it
|
||||||
|
also requires experimental mode (see "experimental-mode on").
|
||||||
|
|
||||||
del map <map> [<key>|#<ref>]
|
del map <map> [<key>|#<ref>]
|
||||||
Delete all the map entries from the map <map> corresponding to the key <key>.
|
Delete all the map entries from the map <map> corresponding to the key <key>.
|
||||||
<map> is the #<id> or the <name> returned by "show map". If the <ref> is used,
|
<map> is the #<id> or the <name> returned by "show map". If the <ref> is used,
|
||||||
|
|
@ -3335,7 +3356,7 @@ show pools [byname|bysize|byusage] [detailed] [match <pfx>] [<nb>]
|
||||||
- Pool quic_conn_c (152 bytes) : 1337 allocated (203224 bytes), ...
|
- Pool quic_conn_c (152 bytes) : 1337 allocated (203224 bytes), ...
|
||||||
Total: 15 pools, 109578176 bytes allocated, 109578176 used ...
|
Total: 15 pools, 109578176 bytes allocated, 109578176 used ...
|
||||||
|
|
||||||
show profiling [{all | status | tasks | memory}] [byaddr|bytime|aggr|<max_lines>]*
|
show profiling [{all | status | tasks | memory}] [byaddr|bytime|byctx|aggr|<max_lines>]*
|
||||||
Dumps the current profiling settings, one per line, as well as the command
|
Dumps the current profiling settings, one per line, as well as the command
|
||||||
needed to change them. When tasks profiling is enabled, some per-function
|
needed to change them. When tasks profiling is enabled, some per-function
|
||||||
statistics collected by the scheduler will also be emitted, with a summary
|
statistics collected by the scheduler will also be emitted, with a summary
|
||||||
|
|
@ -3344,14 +3365,15 @@ show profiling [{all | status | tasks | memory}] [byaddr|bytime|aggr|<max_lines>
|
||||||
allocations/releases and their sizes will be reported. It is possible to
|
allocations/releases and their sizes will be reported. It is possible to
|
||||||
limit the dump to only the profiling status, the tasks, or the memory
|
limit the dump to only the profiling status, the tasks, or the memory
|
||||||
profiling by specifying the respective keywords; by default all profiling
|
profiling by specifying the respective keywords; by default all profiling
|
||||||
information are dumped. It is also possible to limit the number of lines
|
information are dumped. It is also possible to limit the number of lines of
|
||||||
of output of each category by specifying a numeric limit. If is possible to
|
of output of each category by specifying a numeric limit. If is possible to
|
||||||
request that the output is sorted by address or by total execution time
|
request that the output is sorted by address, by total execution time, or by
|
||||||
instead of usage, e.g. to ease comparisons between subsequent calls or to
|
calling context instead of usage, e.g. to ease comparisons between subsequent
|
||||||
check what needs to be optimized, and to aggregate task activity by called
|
calls or to check what needs to be optimized, and to aggregate task activity
|
||||||
function instead of seeing the details. Please note that profiling is
|
by called function instead of seeing the details. Please note that profiling
|
||||||
essentially aimed at developers since it gives hints about where CPU cycles
|
is essentially aimed at developers since it gives hints about where CPU
|
||||||
or memory are wasted in the code. There is nothing useful to monitor there.
|
cycles or memory are wasted in the code. There is nothing useful to monitor
|
||||||
|
there.
|
||||||
|
|
||||||
show resolvers [<resolvers section id>]
|
show resolvers [<resolvers section id>]
|
||||||
Dump statistics for the given resolvers section, or all resolvers sections
|
Dump statistics for the given resolvers section, or all resolvers sections
|
||||||
|
|
@ -4526,6 +4548,13 @@ wait { -h | <delay> } [<condition> [<args>...]]
|
||||||
specified condition to be satisfied, to unrecoverably fail, or to remain
|
specified condition to be satisfied, to unrecoverably fail, or to remain
|
||||||
unsatisfied for the whole <delay> duration. The supported conditions are:
|
unsatisfied for the whole <delay> duration. The supported conditions are:
|
||||||
|
|
||||||
|
- be-removable <proxy> : this will wait for the specified proxy backend to be
|
||||||
|
removable by the "del backend" command. Some conditions will never be
|
||||||
|
accepted (e.g. backend not yet unpublished or with servers in it) and will
|
||||||
|
cause the report of a specific error message indicating what condition is
|
||||||
|
not met. If everything is OK before the delay, a success is returned and
|
||||||
|
the operation is terminated.
|
||||||
|
|
||||||
- srv-removable <proxy>/<server> : this will wait for the specified server to
|
- srv-removable <proxy>/<server> : this will wait for the specified server to
|
||||||
be removable by the "del server" command, i.e. be in maintenance and no
|
be removable by the "del server" command, i.e. be in maintenance and no
|
||||||
longer have any connection on it (neither active or idle). Some conditions
|
longer have any connection on it (neither active or idle). Some conditions
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ struct acme_auth {
|
||||||
struct ist auth; /* auth URI */
|
struct ist auth; /* auth URI */
|
||||||
struct ist chall; /* challenge URI */
|
struct ist chall; /* challenge URI */
|
||||||
struct ist token; /* token */
|
struct ist token; /* token */
|
||||||
|
int validated; /* already validated */
|
||||||
int ready; /* is the challenge ready ? */
|
int ready; /* is the challenge ready ? */
|
||||||
void *next;
|
void *next;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,11 @@ struct act_rule {
|
||||||
struct server *srv; /* target server to attach the connection */
|
struct server *srv; /* target server to attach the connection */
|
||||||
struct sample_expr *name; /* used to differentiate idle connections */
|
struct sample_expr *name; /* used to differentiate idle connections */
|
||||||
} attach_srv; /* 'attach-srv' rule */
|
} attach_srv; /* 'attach-srv' rule */
|
||||||
|
struct {
|
||||||
|
enum log_orig_id orig;
|
||||||
|
char *profile_name;
|
||||||
|
struct log_profile *profile;
|
||||||
|
} do_log; /* 'do-log' action */
|
||||||
struct {
|
struct {
|
||||||
int value;
|
int value;
|
||||||
struct sample_expr *expr;
|
struct sample_expr *expr;
|
||||||
|
|
@ -206,6 +211,7 @@ struct act_rule {
|
||||||
void *p[4];
|
void *p[4];
|
||||||
} act; /* generic pointers to be used by custom actions */
|
} act; /* generic pointers to be used by custom actions */
|
||||||
} arg; /* arguments used by some actions */
|
} arg; /* arguments used by some actions */
|
||||||
|
struct thread_exec_ctx exec_ctx; /* execution context */
|
||||||
struct {
|
struct {
|
||||||
char *file; /* file name where the rule appears (or NULL) */
|
char *file; /* file name where the rule appears (or NULL) */
|
||||||
int line; /* line number where the rule appears */
|
int line; /* line number where the rule appears */
|
||||||
|
|
@ -217,7 +223,9 @@ struct action_kw {
|
||||||
enum act_parse_ret (*parse)(const char **args, int *cur_arg, struct proxy *px,
|
enum act_parse_ret (*parse)(const char **args, int *cur_arg, struct proxy *px,
|
||||||
struct act_rule *rule, char **err);
|
struct act_rule *rule, char **err);
|
||||||
int flags;
|
int flags;
|
||||||
|
/* 4 bytes here */
|
||||||
void *private;
|
void *private;
|
||||||
|
struct thread_exec_ctx exec_ctx; /* execution context */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct action_kw_list {
|
struct action_kw_list {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ int act_resolution_cb(struct resolv_requester *requester, struct dns_counters *c
|
||||||
int act_resolution_error_cb(struct resolv_requester *requester, int error_code);
|
int act_resolution_error_cb(struct resolv_requester *requester, int error_code);
|
||||||
const char *action_suggest(const char *word, const struct list *keywords, const char **extra);
|
const char *action_suggest(const char *word, const struct list *keywords, const char **extra);
|
||||||
void free_act_rule(struct act_rule *rule);
|
void free_act_rule(struct act_rule *rule);
|
||||||
|
void act_add_list(struct list *head, struct action_kw_list *kw_list);
|
||||||
|
|
||||||
static inline struct action_kw *action_lookup(struct list *keywords, const char *kw)
|
static inline struct action_kw *action_lookup(struct list *keywords, const char *kw)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <haproxy/api-t.h>
|
#include <haproxy/api-t.h>
|
||||||
#include <haproxy/freq_ctr-t.h>
|
#include <haproxy/freq_ctr-t.h>
|
||||||
|
#include <haproxy/tinfo-t.h>
|
||||||
|
|
||||||
/* bit fields for the "profiling" global variable */
|
/* bit fields for the "profiling" global variable */
|
||||||
#define HA_PROF_TASKS_OFF 0x00000000 /* per-task CPU profiling forced disabled */
|
#define HA_PROF_TASKS_OFF 0x00000000 /* per-task CPU profiling forced disabled */
|
||||||
|
|
@ -84,6 +85,7 @@ struct memprof_stats {
|
||||||
unsigned long long alloc_tot;
|
unsigned long long alloc_tot;
|
||||||
unsigned long long free_tot;
|
unsigned long long free_tot;
|
||||||
void *info; // for pools, ptr to the pool
|
void *info; // for pools, ptr to the pool
|
||||||
|
struct thread_exec_ctx exec_ctx;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ struct appctx {
|
||||||
int (*io_handler)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK */
|
int (*io_handler)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK */
|
||||||
void (*io_release)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK,
|
void (*io_release)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK,
|
||||||
if the command is terminated or the session released */
|
if the command is terminated or the session released */
|
||||||
|
struct cli_kw *kw; /* the keyword being processed */
|
||||||
} cli_ctx; /* context dedicated to the CLI applet */
|
} cli_ctx; /* context dedicated to the CLI applet */
|
||||||
|
|
||||||
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */
|
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,13 @@ ssize_t applet_append_line(void *ctx, struct ist v1, struct ist v2, size_t ofs,
|
||||||
static forceinline void applet_fl_set(struct appctx *appctx, uint on);
|
static forceinline void applet_fl_set(struct appctx *appctx, uint on);
|
||||||
static forceinline void applet_fl_clr(struct appctx *appctx, uint off);
|
static forceinline void applet_fl_clr(struct appctx *appctx, uint off);
|
||||||
|
|
||||||
|
/* macros to switch the calling context to the applet during a call. There's
|
||||||
|
* one with a return value for most calls, and one without for the few like
|
||||||
|
* fct(), shut(), or release() with no return.
|
||||||
|
*/
|
||||||
|
#define CALL_APPLET_WITH_RET(applet, func) EXEC_CTX_WITH_RET(EXEC_CTX_MAKE(TH_EX_CTX_APPLET, (applet)), (applet)->func)
|
||||||
|
#define CALL_APPLET_NO_RET(applet, func) EXEC_CTX_NO_RET(EXEC_CTX_MAKE(TH_EX_CTX_APPLET, (applet)), (applet)->func)
|
||||||
|
|
||||||
|
|
||||||
static forceinline uint appctx_app_test(const struct appctx *appctx, uint test)
|
static forceinline uint appctx_app_test(const struct appctx *appctx, uint test)
|
||||||
{
|
{
|
||||||
|
|
@ -126,7 +133,7 @@ static inline int appctx_init(struct appctx *appctx)
|
||||||
task_set_thread(appctx->t, tid);
|
task_set_thread(appctx->t, tid);
|
||||||
|
|
||||||
if (appctx->applet->init)
|
if (appctx->applet->init)
|
||||||
return appctx->applet->init(appctx);
|
return CALL_APPLET_WITH_RET(appctx->applet, init(appctx));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -376,6 +376,7 @@ static inline void channel_add_input(struct channel *chn, unsigned int len)
|
||||||
c_adv(chn, fwd);
|
c_adv(chn, fwd);
|
||||||
}
|
}
|
||||||
/* notify that some data was read */
|
/* notify that some data was read */
|
||||||
|
chn_prod(chn)->bytes_in += len;
|
||||||
chn->flags |= CF_READ_EVENT;
|
chn->flags |= CF_READ_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ enum chk_result {
|
||||||
#define CHK_ST_FASTINTER 0x0400 /* force fastinter check */
|
#define CHK_ST_FASTINTER 0x0400 /* force fastinter check */
|
||||||
#define CHK_ST_READY 0x0800 /* check ready to migrate or run, see below */
|
#define CHK_ST_READY 0x0800 /* check ready to migrate or run, see below */
|
||||||
#define CHK_ST_SLEEPING 0x1000 /* check was sleeping, i.e. not currently bound to a thread, see below */
|
#define CHK_ST_SLEEPING 0x1000 /* check was sleeping, i.e. not currently bound to a thread, see below */
|
||||||
|
#define CHK_ST_USE_SMALL_BUFF 0x2000 /* Use small buffers if possible for the request */
|
||||||
|
|
||||||
/* 4 possible states for CHK_ST_SLEEPING and CHK_ST_READY:
|
/* 4 possible states for CHK_ST_SLEEPING and CHK_ST_READY:
|
||||||
* SLP RDY State Description
|
* SLP RDY State Description
|
||||||
|
|
@ -188,6 +189,7 @@ struct check {
|
||||||
char **envp; /* the environment to use if running a process-based check */
|
char **envp; /* the environment to use if running a process-based check */
|
||||||
struct pid_list *curpid; /* entry in pid_list used for current process-based test, or -1 if not in test */
|
struct pid_list *curpid; /* entry in pid_list used for current process-based test, or -1 if not in test */
|
||||||
struct sockaddr_storage addr; /* the address to check */
|
struct sockaddr_storage addr; /* the address to check */
|
||||||
|
struct protocol *proto; /* protocol used for check, may be different from the server's one */
|
||||||
char *pool_conn_name; /* conn name used on reuse */
|
char *pool_conn_name; /* conn name used on reuse */
|
||||||
char *sni; /* Server name */
|
char *sni; /* Server name */
|
||||||
char *alpn_str; /* ALPN to use for checks */
|
char *alpn_str; /* ALPN to use for checks */
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,11 @@ struct task *process_chk(struct task *t, void *context, unsigned int state);
|
||||||
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state);
|
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state);
|
||||||
|
|
||||||
int check_buf_available(void *target);
|
int check_buf_available(void *target);
|
||||||
struct buffer *check_get_buf(struct check *check, struct buffer *bptr);
|
struct buffer *check_get_buf(struct check *check, struct buffer *bptr, unsigned int small_buffer);
|
||||||
void check_release_buf(struct check *check, struct buffer *bptr);
|
void check_release_buf(struct check *check, struct buffer *bptr);
|
||||||
const char *init_check(struct check *check, int type);
|
const char *init_check(struct check *check, int type);
|
||||||
void free_check(struct check *check);
|
void free_check(struct check *check);
|
||||||
void check_purge(struct check *check);
|
void check_purge(struct check *check);
|
||||||
int wake_srv_chk(struct stconn *sc);
|
|
||||||
|
|
||||||
int init_srv_check(struct server *srv);
|
int init_srv_check(struct server *srv);
|
||||||
int init_srv_agent_check(struct server *srv);
|
int init_srv_agent_check(struct server *srv);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
extern struct pool_head *pool_head_trash;
|
extern struct pool_head *pool_head_trash;
|
||||||
extern struct pool_head *pool_head_large_trash;
|
extern struct pool_head *pool_head_large_trash;
|
||||||
|
extern struct pool_head *pool_head_small_trash;
|
||||||
|
|
||||||
/* function prototypes */
|
/* function prototypes */
|
||||||
|
|
||||||
|
|
@ -48,6 +49,7 @@ int chunk_strcmp(const struct buffer *chk, const char *str);
|
||||||
int chunk_strcasecmp(const struct buffer *chk, const char *str);
|
int chunk_strcasecmp(const struct buffer *chk, const char *str);
|
||||||
struct buffer *get_trash_chunk(void);
|
struct buffer *get_trash_chunk(void);
|
||||||
struct buffer *get_large_trash_chunk(void);
|
struct buffer *get_large_trash_chunk(void);
|
||||||
|
struct buffer *get_small_trash_chunk(void);
|
||||||
struct buffer *get_trash_chunk_sz(size_t size);
|
struct buffer *get_trash_chunk_sz(size_t size);
|
||||||
struct buffer *get_larger_trash_chunk(struct buffer *chunk);
|
struct buffer *get_larger_trash_chunk(struct buffer *chunk);
|
||||||
int init_trash_buffers(int first);
|
int init_trash_buffers(int first);
|
||||||
|
|
@ -133,6 +135,29 @@ static forceinline struct buffer *alloc_large_trash_chunk(void)
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a small trash chunk from the reentrant pool. The buffer starts at
|
||||||
|
* the end of the chunk. This chunk must be freed using free_trash_chunk(). This
|
||||||
|
* call may fail and the caller is responsible for checking that the returned
|
||||||
|
* pointer is not NULL.
|
||||||
|
*/
|
||||||
|
static forceinline struct buffer *alloc_small_trash_chunk(void)
|
||||||
|
{
|
||||||
|
struct buffer *chunk;
|
||||||
|
|
||||||
|
if (!pool_head_small_trash)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
chunk = pool_alloc(pool_head_small_trash);
|
||||||
|
if (chunk) {
|
||||||
|
char *buf = (char *)chunk + sizeof(struct buffer);
|
||||||
|
*buf = 0;
|
||||||
|
chunk_init(chunk, buf,
|
||||||
|
pool_head_small_trash->size - sizeof(struct buffer));
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a trash chunk accordingly to the requested size. This chunk must be
|
* Allocate a trash chunk accordingly to the requested size. This chunk must be
|
||||||
* freed using free_trash_chunk(). This call may fail and the caller is
|
* freed using free_trash_chunk(). This call may fail and the caller is
|
||||||
|
|
@ -140,7 +165,9 @@ static forceinline struct buffer *alloc_large_trash_chunk(void)
|
||||||
*/
|
*/
|
||||||
static forceinline struct buffer *alloc_trash_chunk_sz(size_t size)
|
static forceinline struct buffer *alloc_trash_chunk_sz(size_t size)
|
||||||
{
|
{
|
||||||
if (likely(size <= pool_head_trash->size))
|
if (pool_head_small_trash && size <= pool_head_small_trash->size)
|
||||||
|
return alloc_small_trash_chunk();
|
||||||
|
else if (size <= pool_head_trash->size)
|
||||||
return alloc_trash_chunk();
|
return alloc_trash_chunk();
|
||||||
else if (pool_head_large_trash && size <= pool_head_large_trash->size)
|
else if (pool_head_large_trash && size <= pool_head_large_trash->size)
|
||||||
return alloc_large_trash_chunk();
|
return alloc_large_trash_chunk();
|
||||||
|
|
@ -153,10 +180,12 @@ static forceinline struct buffer *alloc_trash_chunk_sz(size_t size)
|
||||||
*/
|
*/
|
||||||
static forceinline void free_trash_chunk(struct buffer *chunk)
|
static forceinline void free_trash_chunk(struct buffer *chunk)
|
||||||
{
|
{
|
||||||
if (likely(chunk && chunk->size == pool_head_trash->size - sizeof(struct buffer)))
|
if (pool_head_small_trash && chunk && chunk->size == pool_head_small_trash->size - sizeof(struct buffer))
|
||||||
pool_free(pool_head_trash, chunk);
|
pool_free(pool_head_small_trash, chunk);
|
||||||
else
|
else if (pool_head_large_trash && chunk && chunk->size == pool_head_large_trash->size - sizeof(struct buffer))
|
||||||
pool_free(pool_head_large_trash, chunk);
|
pool_free(pool_head_large_trash, chunk);
|
||||||
|
else
|
||||||
|
pool_free(pool_head_trash, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copies chunk <src> into <chk>. Returns 0 in case of failure. */
|
/* copies chunk <src> into <chk>. Returns 0 in case of failure. */
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#define _HAPROXY_CLI_T_H
|
#define _HAPROXY_CLI_T_H
|
||||||
|
|
||||||
#include <haproxy/applet-t.h>
|
#include <haproxy/applet-t.h>
|
||||||
|
#include <haproxy/tinfo-t.h>
|
||||||
|
|
||||||
/* Access level for a stats socket (appctx->cli_ctx.level) */
|
/* Access level for a stats socket (appctx->cli_ctx.level) */
|
||||||
#define ACCESS_LVL_NONE 0x0000
|
#define ACCESS_LVL_NONE 0x0000
|
||||||
|
|
@ -100,6 +101,7 @@ enum cli_wait_err {
|
||||||
enum cli_wait_cond {
|
enum cli_wait_cond {
|
||||||
CLI_WAIT_COND_NONE, // no condition to wait on
|
CLI_WAIT_COND_NONE, // no condition to wait on
|
||||||
CLI_WAIT_COND_SRV_UNUSED,// wait for server to become unused
|
CLI_WAIT_COND_SRV_UNUSED,// wait for server to become unused
|
||||||
|
CLI_WAIT_COND_BE_UNUSED, // wait for backend to become unused
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cli_wait_ctx {
|
struct cli_wait_ctx {
|
||||||
|
|
@ -119,6 +121,8 @@ struct cli_kw {
|
||||||
void (*io_release)(struct appctx *appctx);
|
void (*io_release)(struct appctx *appctx);
|
||||||
void *private;
|
void *private;
|
||||||
int level; /* this is the level needed to show the keyword usage and to use it */
|
int level; /* this is the level needed to show the keyword usage and to use it */
|
||||||
|
/* 4-byte hole here */
|
||||||
|
struct thread_exec_ctx exec_ctx; /* execution context */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cli_kw_list {
|
struct cli_kw_list {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
#include <haproxy/listener-t.h>
|
#include <haproxy/listener-t.h>
|
||||||
#include <haproxy/obj_type.h>
|
#include <haproxy/obj_type.h>
|
||||||
#include <haproxy/pool-t.h>
|
#include <haproxy/pool-t.h>
|
||||||
|
#include <haproxy/protocol.h>
|
||||||
#include <haproxy/server.h>
|
#include <haproxy/server.h>
|
||||||
#include <haproxy/session-t.h>
|
#include <haproxy/session-t.h>
|
||||||
#include <haproxy/task-t.h>
|
#include <haproxy/task-t.h>
|
||||||
|
|
@ -49,6 +50,13 @@ extern struct mux_stopping_data mux_stopping_data[MAX_THREADS];
|
||||||
|
|
||||||
#define IS_HTX_CONN(conn) ((conn)->mux && ((conn)->mux->flags & MX_FL_HTX))
|
#define IS_HTX_CONN(conn) ((conn)->mux && ((conn)->mux->flags & MX_FL_HTX))
|
||||||
|
|
||||||
|
/* macros to switch the calling context to the mux during a call. There's one
|
||||||
|
* with a return value for most calls, and one without for the few like shut(),
|
||||||
|
* detach() or destroy() with no return.
|
||||||
|
*/
|
||||||
|
#define CALL_MUX_WITH_RET(mux, func) EXEC_CTX_WITH_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
|
||||||
|
#define CALL_MUX_NO_RET(mux, func) EXEC_CTX_NO_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
|
||||||
|
|
||||||
/* receive a PROXY protocol header over a connection */
|
/* receive a PROXY protocol header over a connection */
|
||||||
int conn_recv_proxy(struct connection *conn, int flag);
|
int conn_recv_proxy(struct connection *conn, int flag);
|
||||||
int conn_send_proxy(struct connection *conn, unsigned int flag);
|
int conn_send_proxy(struct connection *conn, unsigned int flag);
|
||||||
|
|
@ -480,7 +488,7 @@ static inline int conn_install_mux(struct connection *conn, const struct mux_ops
|
||||||
|
|
||||||
conn->mux = mux;
|
conn->mux = mux;
|
||||||
conn->ctx = ctx;
|
conn->ctx = ctx;
|
||||||
ret = mux->init ? mux->init(conn, prx, sess, &BUF_NULL) : 0;
|
ret = mux->init ? CALL_MUX_WITH_RET(mux, init(conn, prx, sess, &BUF_NULL)) : 0;
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
conn->mux = NULL;
|
conn->mux = NULL;
|
||||||
conn->ctx = NULL;
|
conn->ctx = NULL;
|
||||||
|
|
@ -602,13 +610,13 @@ void list_mux_proto(FILE *out);
|
||||||
*/
|
*/
|
||||||
static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
||||||
const struct ist mux_proto,
|
const struct ist mux_proto,
|
||||||
int proto_side, int proto_mode)
|
int proto_side, int proto_is_quic, int proto_mode)
|
||||||
{
|
{
|
||||||
struct mux_proto_list *item;
|
struct mux_proto_list *item;
|
||||||
struct mux_proto_list *fallback = NULL;
|
struct mux_proto_list *fallback = NULL;
|
||||||
|
|
||||||
list_for_each_entry(item, &mux_proto_list.list, list) {
|
list_for_each_entry(item, &mux_proto_list.list, list) {
|
||||||
if (!(item->side & proto_side) || !(item->mode & proto_mode))
|
if (!(item->side & proto_side) || !(item->mode & proto_mode) || (proto_is_quic && !(item->mux->flags & MX_FL_FRAMED)))
|
||||||
continue;
|
continue;
|
||||||
if (istlen(mux_proto) && isteq(mux_proto, item->token))
|
if (istlen(mux_proto) && isteq(mux_proto, item->token))
|
||||||
return item;
|
return item;
|
||||||
|
|
@ -633,7 +641,7 @@ static inline const struct mux_ops *conn_get_best_mux(struct connection *conn,
|
||||||
{
|
{
|
||||||
const struct mux_proto_list *item;
|
const struct mux_proto_list *item;
|
||||||
|
|
||||||
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_mode);
|
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode);
|
||||||
|
|
||||||
return item ? item->mux : NULL;
|
return item ? item->mux : NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,29 @@ struct be_counters {
|
||||||
} p; /* protocol-specific stats */
|
} p; /* protocol-specific stats */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* extra counters that are registered at boot by various modules */
|
||||||
|
enum counters_type {
|
||||||
|
COUNTERS_FE = 0,
|
||||||
|
COUNTERS_BE,
|
||||||
|
COUNTERS_SV,
|
||||||
|
COUNTERS_LI,
|
||||||
|
COUNTERS_RSLV,
|
||||||
|
|
||||||
|
COUNTERS_OFF_END /* must always be last */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct extra_counters {
|
||||||
|
char **datap; /* points to pointer to heap containing counters allocated in a linear fashion */
|
||||||
|
size_t size; /* size of allocated data */
|
||||||
|
size_t tgrp_step; /* distance in words between two datap for consecutive tgroups, 0 for single */
|
||||||
|
uint nbtgrp; /* number of thread groups accessing these counters */
|
||||||
|
enum counters_type type; /* type of object containing the counters */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define EXTRA_COUNTERS(name) \
|
||||||
|
struct extra_counters *name
|
||||||
|
|
||||||
#endif /* _HAPROXY_COUNTERS_T_H */
|
#endif /* _HAPROXY_COUNTERS_T_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@
|
||||||
|
|
||||||
#include <haproxy/counters-t.h>
|
#include <haproxy/counters-t.h>
|
||||||
#include <haproxy/guid-t.h>
|
#include <haproxy/guid-t.h>
|
||||||
|
#include <haproxy/global.h>
|
||||||
|
|
||||||
|
extern THREAD_LOCAL void *trash_counters;
|
||||||
|
|
||||||
int counters_fe_shared_prepare(struct fe_counters_shared *counters, const struct guid_node *guid, char **errmsg);
|
int counters_fe_shared_prepare(struct fe_counters_shared *counters, const struct guid_node *guid, char **errmsg);
|
||||||
int counters_be_shared_prepare(struct be_counters_shared *counters, const struct guid_node *guid, char **errmsg);
|
int counters_be_shared_prepare(struct be_counters_shared *counters, const struct guid_node *guid, char **errmsg);
|
||||||
|
|
@ -101,4 +104,106 @@ void counters_be_shared_drop(struct be_counters_shared *counters);
|
||||||
__ret; \
|
__ret; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define COUNTERS_UPDATE_MAX(counter, count) \
|
||||||
|
do { \
|
||||||
|
if (!(global.tune.options & GTUNE_NO_MAX_COUNTER)) \
|
||||||
|
HA_ATOMIC_UPDATE_MAX(counter, count); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Manipulation of extra_counters, for boot-time registrable modules */
|
||||||
|
/* retrieve the base storage of extra counters (first tgroup if any) */
|
||||||
|
#define EXTRA_COUNTERS_BASE(counters, mod) \
|
||||||
|
(likely(counters) ? \
|
||||||
|
((void *)(*(counters)->datap + (mod)->counters_off[(counters)->type])) : \
|
||||||
|
(trash_counters))
|
||||||
|
|
||||||
|
/* retrieve the pointer to the extra counters storage for module <mod> for the
|
||||||
|
* current TGID.
|
||||||
|
*/
|
||||||
|
#define EXTRA_COUNTERS_GET(counters, mod) \
|
||||||
|
(likely(counters) ? \
|
||||||
|
((void *)(counters)->datap[(counters)->tgrp_step * (tgid - 1)] + \
|
||||||
|
(mod)->counters_off[(counters)->type]) : \
|
||||||
|
(trash_counters))
|
||||||
|
|
||||||
|
#define EXTRA_COUNTERS_REGISTER(counters, ctype, alloc_failed_label, storage, step) \
|
||||||
|
do { \
|
||||||
|
typeof(*counters) _ctr; \
|
||||||
|
_ctr = calloc(1, sizeof(*_ctr)); \
|
||||||
|
if (!_ctr) \
|
||||||
|
goto alloc_failed_label; \
|
||||||
|
_ctr->type = (ctype); \
|
||||||
|
_ctr->tgrp_step = (step); \
|
||||||
|
_ctr->datap = (storage); \
|
||||||
|
*(counters) = _ctr; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXTRA_COUNTERS_ADD(mod, counters, new_counters, csize) \
|
||||||
|
do { \
|
||||||
|
typeof(counters) _ctr = (counters); \
|
||||||
|
(mod)->counters_off[_ctr->type] = _ctr->size; \
|
||||||
|
_ctr->size += (csize); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXTRA_COUNTERS_ALLOC(counters, alloc_failed_label, nbtg) \
|
||||||
|
do { \
|
||||||
|
typeof(counters) _ctr = (counters); \
|
||||||
|
char **datap = _ctr->datap; \
|
||||||
|
uint tgrp; \
|
||||||
|
_ctr->nbtgrp = _ctr->tgrp_step ? (nbtg) : 1; \
|
||||||
|
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
|
||||||
|
*datap = malloc((_ctr)->size); \
|
||||||
|
if (!*_ctr->datap) \
|
||||||
|
goto alloc_failed_label; \
|
||||||
|
datap += _ctr->tgrp_step; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXTRA_COUNTERS_INIT(counters, mod, init_counters, init_counters_size) \
|
||||||
|
do { \
|
||||||
|
typeof(counters) _ctr = (counters); \
|
||||||
|
char **datap = _ctr->datap; \
|
||||||
|
uint tgrp; \
|
||||||
|
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
|
||||||
|
memcpy(*datap + mod->counters_off[_ctr->type], \
|
||||||
|
(init_counters), (init_counters_size)); \
|
||||||
|
datap += _ctr->tgrp_step; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXTRA_COUNTERS_FREE(counters) \
|
||||||
|
do { \
|
||||||
|
typeof(counters) _ctr = (counters); \
|
||||||
|
if (_ctr) { \
|
||||||
|
char **datap = _ctr->datap; \
|
||||||
|
uint tgrp; \
|
||||||
|
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
|
||||||
|
ha_free(datap); \
|
||||||
|
datap += _ctr->tgrp_step; \
|
||||||
|
} \
|
||||||
|
free(_ctr); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* aggregate all values of <metricp> over the thread groups handled by
|
||||||
|
* <counters>. <metricp> MUST correspond to an entry of the first tgrp of
|
||||||
|
* <counters>. The number of groups and the step are found in <counters>. The
|
||||||
|
* type of the return value is the same as <metricp>, and must be a scalar so
|
||||||
|
* that values are summed before being returned.
|
||||||
|
*/
|
||||||
|
#define EXTRA_COUNTERS_AGGR(counters, metricp) \
|
||||||
|
({ \
|
||||||
|
typeof(counters) _ctr = (counters); \
|
||||||
|
typeof(metricp) *valp, _ret = 0; \
|
||||||
|
if (_ctr) { \
|
||||||
|
size_t ofs = (char *)&metricp - _ctr->datap[0]; \
|
||||||
|
uint tgrp; \
|
||||||
|
for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \
|
||||||
|
valp = (typeof(valp))(_ctr->datap[tgrp * (counters)->tgrp_step] + ofs); \
|
||||||
|
_ret += HA_ATOMIC_LOAD(valp); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
_ret; \
|
||||||
|
})
|
||||||
|
|
||||||
#endif /* _HAPROXY_COUNTERS_H */
|
#endif /* _HAPROXY_COUNTERS_H */
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,11 @@
|
||||||
#define TIME_STATS_SAMPLES 512
|
#define TIME_STATS_SAMPLES 512
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* number of samples used to measure the load in the run queue */
|
||||||
|
#ifndef RQ_LOAD_SAMPLES
|
||||||
|
#define RQ_LOAD_SAMPLES 512
|
||||||
|
#endif
|
||||||
|
|
||||||
/* max ocsp cert id asn1 encoded length */
|
/* max ocsp cert id asn1 encoded length */
|
||||||
#ifndef OCSP_MAX_CERTID_ASN1_LENGTH
|
#ifndef OCSP_MAX_CERTID_ASN1_LENGTH
|
||||||
#define OCSP_MAX_CERTID_ASN1_LENGTH 128
|
#define OCSP_MAX_CERTID_ASN1_LENGTH 128
|
||||||
|
|
@ -601,7 +606,7 @@
|
||||||
* store stats.
|
* store stats.
|
||||||
*/
|
*/
|
||||||
#ifndef MEMPROF_HASH_BITS
|
#ifndef MEMPROF_HASH_BITS
|
||||||
# define MEMPROF_HASH_BITS 10
|
# define MEMPROF_HASH_BITS 12
|
||||||
#endif
|
#endif
|
||||||
#define MEMPROF_HASH_BUCKETS (1U << MEMPROF_HASH_BITS)
|
#define MEMPROF_HASH_BUCKETS (1U << MEMPROF_HASH_BITS)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@
|
||||||
|
|
||||||
#include <import/ebtree-t.h>
|
#include <import/ebtree-t.h>
|
||||||
|
|
||||||
#include <haproxy/connection-t.h>
|
|
||||||
#include <haproxy/buf-t.h>
|
#include <haproxy/buf-t.h>
|
||||||
|
#include <haproxy/connection-t.h>
|
||||||
|
#include <haproxy/counters-t.h>
|
||||||
#include <haproxy/dgram-t.h>
|
#include <haproxy/dgram-t.h>
|
||||||
#include <haproxy/dns_ring-t.h>
|
#include <haproxy/dns_ring-t.h>
|
||||||
#include <haproxy/obj_type-t.h>
|
#include <haproxy/obj_type-t.h>
|
||||||
#include <haproxy/stats-t.h>
|
|
||||||
#include <haproxy/task-t.h>
|
#include <haproxy/task-t.h>
|
||||||
#include <haproxy/thread.h>
|
#include <haproxy/thread.h>
|
||||||
|
|
||||||
|
|
@ -152,6 +152,7 @@ struct dns_nameserver {
|
||||||
struct dns_stream_server *stream; /* used for tcp dns */
|
struct dns_stream_server *stream; /* used for tcp dns */
|
||||||
|
|
||||||
EXTRA_COUNTERS(extra_counters);
|
EXTRA_COUNTERS(extra_counters);
|
||||||
|
char *extra_counters_storage; /* storage used for extra_counters above */
|
||||||
struct dns_counters *counters;
|
struct dns_counters *counters;
|
||||||
|
|
||||||
struct list list; /* nameserver chained list */
|
struct list list; /* nameserver chained list */
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
extern struct pool_head *pool_head_buffer;
|
extern struct pool_head *pool_head_buffer;
|
||||||
extern struct pool_head *pool_head_large_buffer;
|
extern struct pool_head *pool_head_large_buffer;
|
||||||
|
extern struct pool_head *pool_head_small_buffer;
|
||||||
|
|
||||||
int init_buffer(void);
|
int init_buffer(void);
|
||||||
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
|
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
|
||||||
|
|
@ -66,6 +67,12 @@ static inline int b_is_large_sz(size_t sz)
|
||||||
return (pool_head_large_buffer && sz == pool_head_large_buffer->size);
|
return (pool_head_large_buffer && sz == pool_head_large_buffer->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return 1 if <sz> is the size of a small buffer */
|
||||||
|
static inline int b_is_small_sz(size_t sz)
|
||||||
|
{
|
||||||
|
return (pool_head_small_buffer && sz == pool_head_small_buffer->size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return 1 if <bug> is a default buffer */
|
/* Return 1 if <bug> is a default buffer */
|
||||||
static inline int b_is_default(struct buffer *buf)
|
static inline int b_is_default(struct buffer *buf)
|
||||||
{
|
{
|
||||||
|
|
@ -78,6 +85,12 @@ static inline int b_is_large(struct buffer *buf)
|
||||||
return b_is_large_sz(b_size(buf));
|
return b_is_large_sz(b_size(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return 1 if <buf> is a small buffer */
|
||||||
|
static inline int b_is_small(struct buffer *buf)
|
||||||
|
{
|
||||||
|
return b_is_small_sz(b_size(buf));
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
/* Functions below are used for buffer allocation */
|
/* Functions below are used for buffer allocation */
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
|
|
@ -172,6 +185,8 @@ static inline char *__b_get_emergency_buf(void)
|
||||||
* than the default buffers */ \
|
* than the default buffers */ \
|
||||||
if (unlikely(b_is_large_sz(sz))) \
|
if (unlikely(b_is_large_sz(sz))) \
|
||||||
pool_free(pool_head_large_buffer, area); \
|
pool_free(pool_head_large_buffer, area); \
|
||||||
|
else if (unlikely(b_is_small_sz(sz))) \
|
||||||
|
pool_free(pool_head_small_buffer, area); \
|
||||||
else if (th_ctx->emergency_bufs_left < global.tune.reserved_bufs) \
|
else if (th_ctx->emergency_bufs_left < global.tune.reserved_bufs) \
|
||||||
th_ctx->emergency_bufs[th_ctx->emergency_bufs_left++] = area; \
|
th_ctx->emergency_bufs[th_ctx->emergency_bufs_left++] = area; \
|
||||||
else \
|
else \
|
||||||
|
|
@ -185,6 +200,35 @@ static inline char *__b_get_emergency_buf(void)
|
||||||
__b_free((_buf)); \
|
__b_free((_buf)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct buffer *b_alloc_small(struct buffer *buf)
|
||||||
|
{
|
||||||
|
char *area = NULL;
|
||||||
|
|
||||||
|
if (!buf->size) {
|
||||||
|
area = pool_alloc(pool_head_small_buffer);
|
||||||
|
if (!area)
|
||||||
|
return NULL;
|
||||||
|
buf->area = area;
|
||||||
|
buf->size = global.tune.bufsize_small;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct buffer *b_alloc_large(struct buffer *buf)
|
||||||
|
{
|
||||||
|
char *area = NULL;
|
||||||
|
|
||||||
|
if (!buf->size) {
|
||||||
|
area = pool_alloc(pool_head_large_buffer);
|
||||||
|
if (!area)
|
||||||
|
return NULL;
|
||||||
|
buf->area = area;
|
||||||
|
buf->size = global.tune.bufsize_large;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
/* Offer one or multiple buffer currently belonging to target <from> to whoever
|
/* Offer one or multiple buffer currently belonging to target <from> to whoever
|
||||||
* needs one. Any pointer is valid for <from>, including NULL. Its purpose is
|
* needs one. Any pointer is valid for <from>, including NULL. Its purpose is
|
||||||
* to avoid passing a buffer to oneself in case of failed allocations (e.g.
|
* to avoid passing a buffer to oneself in case of failed allocations (e.g.
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,9 @@
|
||||||
#include <haproxy/stream-t.h>
|
#include <haproxy/stream-t.h>
|
||||||
|
|
||||||
extern const char *trace_flt_id;
|
extern const char *trace_flt_id;
|
||||||
extern const char *http_comp_flt_id;
|
extern const char *http_comp_req_flt_id;
|
||||||
|
extern const char *http_comp_res_flt_id;
|
||||||
|
|
||||||
extern const char *cache_store_flt_id;
|
extern const char *cache_store_flt_id;
|
||||||
extern const char *spoe_filter_id;
|
extern const char *spoe_filter_id;
|
||||||
extern const char *fcgi_flt_id;
|
extern const char *fcgi_flt_id;
|
||||||
|
|
|
||||||
|
|
@ -403,6 +403,25 @@ static inline uint swrate_add_scaled_opportunistic(uint *sum, uint n, uint v, ui
|
||||||
return new_sum;
|
return new_sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Like swrate_add() except that if <v> is beyond the current average, the
|
||||||
|
* average is replaced by the peak. This is essentially used to measure peak
|
||||||
|
* loads in the scheduler, reason why it is provided as a local variant that
|
||||||
|
* does not involve atomic operations.
|
||||||
|
*/
|
||||||
|
static inline uint swrate_add_peak_local(uint *sum, uint n, uint v)
|
||||||
|
{
|
||||||
|
uint old_sum, new_sum;
|
||||||
|
|
||||||
|
old_sum = *sum;
|
||||||
|
if (v * n > old_sum)
|
||||||
|
new_sum = v * n;
|
||||||
|
else
|
||||||
|
new_sum = old_sum - (old_sum + n - 1) / n + v;
|
||||||
|
|
||||||
|
*sum = new_sum;
|
||||||
|
return new_sum;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns the average sample value for the sum <sum> over a sliding window of
|
/* Returns the average sample value for the sum <sum> over a sliding window of
|
||||||
* <n> samples. Better if <n> is a power of two. It must be the same <n> as the
|
* <n> samples. Better if <n> is a power of two. It must be the same <n> as the
|
||||||
* one used above in all additions.
|
* one used above in all additions.
|
||||||
|
|
|
||||||
|
|
@ -79,13 +79,14 @@
|
||||||
#define GTUNE_DISABLE_H2_WEBSOCKET (1<<21)
|
#define GTUNE_DISABLE_H2_WEBSOCKET (1<<21)
|
||||||
#define GTUNE_DISABLE_ACTIVE_CLOSE (1<<22)
|
#define GTUNE_DISABLE_ACTIVE_CLOSE (1<<22)
|
||||||
#define GTUNE_QUICK_EXIT (1<<23)
|
#define GTUNE_QUICK_EXIT (1<<23)
|
||||||
/* (1<<24) unused */
|
#define GTUNE_COLLECT_LIBS (1<<24)
|
||||||
/* (1<<25) unused */
|
/* (1<<25) unused */
|
||||||
#define GTUNE_USE_FAST_FWD (1<<26)
|
#define GTUNE_USE_FAST_FWD (1<<26)
|
||||||
#define GTUNE_LISTENER_MQ_FAIR (1<<27)
|
#define GTUNE_LISTENER_MQ_FAIR (1<<27)
|
||||||
#define GTUNE_LISTENER_MQ_OPT (1<<28)
|
#define GTUNE_LISTENER_MQ_OPT (1<<28)
|
||||||
#define GTUNE_LISTENER_MQ_ANY (GTUNE_LISTENER_MQ_FAIR | GTUNE_LISTENER_MQ_OPT)
|
#define GTUNE_LISTENER_MQ_ANY (GTUNE_LISTENER_MQ_FAIR | GTUNE_LISTENER_MQ_OPT)
|
||||||
#define GTUNE_NO_KTLS (1<<29)
|
#define GTUNE_NO_KTLS (1<<29)
|
||||||
|
#define GTUNE_NO_MAX_COUNTER (1<<30)
|
||||||
|
|
||||||
/* subsystem-specific debugging options for tune.debug */
|
/* subsystem-specific debugging options for tune.debug */
|
||||||
#define GDBG_CPU_AFFINITY (1U<< 0)
|
#define GDBG_CPU_AFFINITY (1U<< 0)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@ extern int devnullfd;
|
||||||
extern int fileless_mode;
|
extern int fileless_mode;
|
||||||
extern struct cfgfile fileless_cfg;
|
extern struct cfgfile fileless_cfg;
|
||||||
|
|
||||||
|
/* storage for collected libs */
|
||||||
|
extern void *lib_storage;
|
||||||
|
extern size_t lib_size;
|
||||||
|
|
||||||
struct proxy;
|
struct proxy;
|
||||||
struct server;
|
struct server;
|
||||||
int main(int argc, char **argv);
|
int main(int argc, char **argv);
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ enum h1m_state {
|
||||||
#define H1_MF_TE_CHUNKED 0x00010000 // T-E "chunked"
|
#define H1_MF_TE_CHUNKED 0x00010000 // T-E "chunked"
|
||||||
#define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now)
|
#define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now)
|
||||||
#define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token
|
#define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token
|
||||||
|
#define H1_MF_NOT_HTTP 0x00080000 // Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted)
|
||||||
/* Mask to use to reset H1M flags when we restart headers parsing.
|
/* Mask to use to reset H1M flags when we restart headers parsing.
|
||||||
*
|
*
|
||||||
* WARNING: Don't forget to update it if a new flag must be preserved when
|
* WARNING: Don't forget to update it if a new flag must be preserved when
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@ struct hlua_proxy_list {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hlua_proxy_list_iterator_context {
|
struct hlua_proxy_list_iterator_context {
|
||||||
|
struct watcher px_watch; /* watcher to automatically update next pointer on backend deletion */
|
||||||
struct proxy *next;
|
struct proxy *next;
|
||||||
char capabilities;
|
char capabilities;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
#include <haproxy/hstream-t.h>
|
#include <haproxy/hstream-t.h>
|
||||||
|
|
||||||
struct task *sc_hstream_io_cb(struct task *t, void *ctx, unsigned int state);
|
struct task *sc_hstream_io_cb(struct task *t, void *ctx, unsigned int state);
|
||||||
int hstream_wake(struct stconn *sc);
|
|
||||||
void hstream_shutdown(struct stconn *sc);
|
void hstream_shutdown(struct stconn *sc);
|
||||||
void *hstream_new(struct session *sess, struct stconn *sc, struct buffer *input);
|
void *hstream_new(struct session *sess, struct stconn *sc, struct buffer *input);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,8 @@ enum h1_state {
|
||||||
*/
|
*/
|
||||||
struct http_msg {
|
struct http_msg {
|
||||||
enum h1_state msg_state; /* where we are in the current message parsing */
|
enum h1_state msg_state; /* where we are in the current message parsing */
|
||||||
/* 3 bytes unused here */
|
unsigned char vsn; /* HTTP version, 4 bits per digit */
|
||||||
|
/* 2 bytes unused here */
|
||||||
unsigned int flags; /* flags describing the message (HTTP version, ...) */
|
unsigned int flags; /* flags describing the message (HTTP version, ...) */
|
||||||
struct channel *chn; /* pointer to the channel transporting the message */
|
struct channel *chn; /* pointer to the channel transporting the message */
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -93,4 +93,22 @@ struct http_errors {
|
||||||
struct list list; /* http-errors list */
|
struct list list; /* http-errors list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Indicates the keyword origin of an http-error definition. This is used in
|
||||||
|
* <conf_errors> type to indicate which part of the internal union should be
|
||||||
|
* manipulated.
|
||||||
|
*/
|
||||||
|
enum http_err_directive {
|
||||||
|
HTTP_ERR_DIRECTIVE_SECTION = 0, /* "errorfiles" keyword referencing a http-errors section */
|
||||||
|
HTTP_ERR_DIRECTIVE_INLINE, /* "errorfile" keyword with inline error definition */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Used with "errorfiles" directives. It indicates for each known HTTP error
|
||||||
|
* status codes if they are defined in the target http-errors section.
|
||||||
|
*/
|
||||||
|
enum http_err_import {
|
||||||
|
HTTP_ERR_IMPORT_NO = 0,
|
||||||
|
HTTP_ERR_IMPORT_IMPLICIT, /* import every errcode defined in a section */
|
||||||
|
HTTP_ERR_IMPORT_EXPLICIT, /* import a specific errcode from a section */
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _HAPROXY_HTTP_HTX_T_H */
|
#endif /* _HAPROXY_HTTP_HTX_T_H */
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ struct buffer *http_load_errorfile(const char *file, char **errmsg);
|
||||||
struct buffer *http_load_errormsg(const char *key, const struct ist msg, char **errmsg);
|
struct buffer *http_load_errormsg(const char *key, const struct ist msg, char **errmsg);
|
||||||
struct buffer *http_parse_errorfile(int status, const char *file, char **errmsg);
|
struct buffer *http_parse_errorfile(int status, const char *file, char **errmsg);
|
||||||
struct buffer *http_parse_errorloc(int errloc, int status, const char *url, char **errmsg);
|
struct buffer *http_parse_errorloc(int errloc, int status, const char *url, char **errmsg);
|
||||||
|
int proxy_check_http_errors(struct proxy *px);
|
||||||
int proxy_dup_default_conf_errors(struct proxy *curpx, const struct proxy *defpx, char **errmsg);
|
int proxy_dup_default_conf_errors(struct proxy *curpx, const struct proxy *defpx, char **errmsg);
|
||||||
void proxy_release_conf_errors(struct proxy *px);
|
void proxy_release_conf_errors(struct proxy *px);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@
|
||||||
#define HTX_SL_F_NORMALIZED_URI 0x00000800 /* The received URI is normalized (an implicit absolute-uri form) */
|
#define HTX_SL_F_NORMALIZED_URI 0x00000800 /* The received URI is normalized (an implicit absolute-uri form) */
|
||||||
#define HTX_SL_F_CONN_UPG 0x00001000 /* The message contains "connection: upgrade" header */
|
#define HTX_SL_F_CONN_UPG 0x00001000 /* The message contains "connection: upgrade" header */
|
||||||
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyloess (only for reqyest) */
|
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyloess (only for reqyest) */
|
||||||
|
#define HTX_SL_F_NOT_HTTP 0x00004000 /* Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted) */
|
||||||
|
|
||||||
/* This function is used to report flags in debugging tools. Please reflect
|
/* This function is used to report flags in debugging tools. Please reflect
|
||||||
* below any single-bit flag addition above in the same order via the
|
* below any single-bit flag addition above in the same order via the
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ struct htx_blk *htx_add_blk(struct htx *htx, enum htx_blk_type type, uint32_t bl
|
||||||
struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk);
|
struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk);
|
||||||
struct htx_ret htx_find_offset(struct htx *htx, uint32_t offset);
|
struct htx_ret htx_find_offset(struct htx *htx, uint32_t offset);
|
||||||
void htx_truncate(struct htx *htx, uint32_t offset);
|
void htx_truncate(struct htx *htx, uint32_t offset);
|
||||||
|
void htx_truncate_blk(struct htx *htx, struct htx_blk *blk);
|
||||||
struct htx_ret htx_drain(struct htx *htx, uint32_t max);
|
struct htx_ret htx_drain(struct htx *htx, uint32_t max);
|
||||||
|
|
||||||
struct htx_blk *htx_replace_blk_value(struct htx *htx, struct htx_blk *blk,
|
struct htx_blk *htx_replace_blk_value(struct htx *htx, struct htx_blk *blk,
|
||||||
|
|
@ -56,6 +57,16 @@ size_t htx_add_data(struct htx *htx, const struct ist data);
|
||||||
struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data);
|
struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data);
|
||||||
void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk **ref);
|
void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk **ref);
|
||||||
int htx_append_msg(struct htx *dst, const struct htx *src);
|
int htx_append_msg(struct htx *dst, const struct htx *src);
|
||||||
|
struct buffer *htx_move_to_small_buffer(struct buffer *dst, struct buffer *src);
|
||||||
|
struct buffer *htx_move_to_large_buffer(struct buffer *dst, struct buffer *src);
|
||||||
|
struct buffer *htx_copy_to_small_buffer(struct buffer *dst, struct buffer *src);
|
||||||
|
struct buffer *htx_copy_to_large_buffer(struct buffer *dst, struct buffer *src);
|
||||||
|
|
||||||
|
#define HTX_XFER_DEFAULT 0x00000000 /* Default XFER: no partial xfer / remove blocks from source */
|
||||||
|
#define HTX_XFER_KEEP_SRC_BLKS 0x00000001 /* Don't remove xfer blocks from source messages during xfer */
|
||||||
|
#define HTX_XFER_PARTIAL_HDRS_COPY 0x00000002 /* Allow partial copy of headers and trailers part */
|
||||||
|
#define HTX_XFER_HDRS_ONLY 0x00000003 /* Only Transfert header blocks (start-line, header and EOH) */
|
||||||
|
size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int flags);
|
||||||
|
|
||||||
/* Functions and macros to get parts of the start-line or length of these
|
/* Functions and macros to get parts of the start-line or length of these
|
||||||
* parts. Request and response start-lines are both composed of 3 parts.
|
* parts. Request and response start-lines are both composed of 3 parts.
|
||||||
|
|
@ -98,6 +109,11 @@ static inline struct ist htx_sl_p3(const struct htx_sl *sl)
|
||||||
return ist2(HTX_SL_P3_PTR(sl), HTX_SL_P3_LEN(sl));
|
return ist2(HTX_SL_P3_PTR(sl), HTX_SL_P3_LEN(sl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct ist htx_sl_vsn(const struct htx_sl *sl)
|
||||||
|
{
|
||||||
|
return ((sl->flags & HTX_SL_F_IS_RESP) ? htx_sl_p1(sl) : htx_sl_p3(sl));
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct ist htx_sl_req_meth(const struct htx_sl *sl)
|
static inline struct ist htx_sl_req_meth(const struct htx_sl *sl)
|
||||||
{
|
{
|
||||||
return htx_sl_p1(sl);
|
return htx_sl_p1(sl);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@ extern struct list server_deinit_list;
|
||||||
extern struct list per_thread_free_list;
|
extern struct list per_thread_free_list;
|
||||||
extern struct list per_thread_deinit_list;
|
extern struct list per_thread_deinit_list;
|
||||||
|
|
||||||
|
/* initcall caller location */
|
||||||
|
extern const struct initcall *caller_initcall;
|
||||||
|
extern const char *caller_file;
|
||||||
|
extern int caller_line;
|
||||||
|
|
||||||
void hap_register_pre_check(int (*fct)());
|
void hap_register_pre_check(int (*fct)());
|
||||||
void hap_register_post_check(int (*fct)());
|
void hap_register_post_check(int (*fct)());
|
||||||
void hap_register_post_proxy_check(int (*fct)(struct proxy *));
|
void hap_register_post_proxy_check(int (*fct)(struct proxy *));
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,8 @@ struct initcall {
|
||||||
void *arg1;
|
void *arg1;
|
||||||
void *arg2;
|
void *arg2;
|
||||||
void *arg3;
|
void *arg3;
|
||||||
|
const char *loc_file; /* file where the call is declared, or NULL */
|
||||||
|
int loc_line; /* line where the call is declared, or NULL */
|
||||||
#if defined(USE_OBSOLETE_LINKER)
|
#if defined(USE_OBSOLETE_LINKER)
|
||||||
void *next;
|
void *next;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -107,6 +109,8 @@ struct initcall {
|
||||||
.arg1 = (void *)(a1), \
|
.arg1 = (void *)(a1), \
|
||||||
.arg2 = (void *)(a2), \
|
.arg2 = (void *)(a2), \
|
||||||
.arg3 = (void *)(a3), \
|
.arg3 = (void *)(a3), \
|
||||||
|
.loc_file = __FILE__, \
|
||||||
|
.loc_line = linenum, \
|
||||||
} : NULL
|
} : NULL
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -131,6 +135,8 @@ __attribute__((constructor)) static void __initcb_##linenum() \
|
||||||
.arg1 = (void *)(a1), \
|
.arg1 = (void *)(a1), \
|
||||||
.arg2 = (void *)(a2), \
|
.arg2 = (void *)(a2), \
|
||||||
.arg3 = (void *)(a3), \
|
.arg3 = (void *)(a3), \
|
||||||
|
.loc_file = __FILE__, \
|
||||||
|
.loc_line = linenum, \
|
||||||
}; \
|
}; \
|
||||||
if (stg < STG_SIZE) { \
|
if (stg < STG_SIZE) { \
|
||||||
entry.next = __initstg[stg]; \
|
entry.next = __initstg[stg]; \
|
||||||
|
|
@ -229,8 +235,15 @@ extern struct initcall *__initstg[STG_SIZE];
|
||||||
const struct initcall **ptr; \
|
const struct initcall **ptr; \
|
||||||
if (stg >= STG_SIZE) \
|
if (stg >= STG_SIZE) \
|
||||||
break; \
|
break; \
|
||||||
FOREACH_INITCALL(ptr, stg) \
|
FOREACH_INITCALL(ptr, stg) { \
|
||||||
|
caller_initcall = *ptr; \
|
||||||
|
caller_file = (*ptr)->loc_file; \
|
||||||
|
caller_line = (*ptr)->loc_line; \
|
||||||
(*ptr)->fct((*ptr)->arg1, (*ptr)->arg2, (*ptr)->arg3); \
|
(*ptr)->fct((*ptr)->arg1, (*ptr)->arg2, (*ptr)->arg3); \
|
||||||
|
caller_initcall = NULL; \
|
||||||
|
caller_file = NULL; \
|
||||||
|
caller_line = 0; \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#else // USE_OBSOLETE_LINKER
|
#else // USE_OBSOLETE_LINKER
|
||||||
|
|
@ -243,8 +256,15 @@ extern struct initcall *__initstg[STG_SIZE];
|
||||||
const struct initcall *ptr; \
|
const struct initcall *ptr; \
|
||||||
if (stg >= STG_SIZE) \
|
if (stg >= STG_SIZE) \
|
||||||
break; \
|
break; \
|
||||||
FOREACH_INITCALL(ptr, stg) \
|
FOREACH_INITCALL(ptr, stg) { \
|
||||||
|
caller_initcall = ptr; \
|
||||||
|
caller_file = (ptr)->loc_file; \
|
||||||
|
caller_line = (ptr)->loc_line; \
|
||||||
(ptr)->fct((ptr)->arg1, (ptr)->arg2, (ptr)->arg3); \
|
(ptr)->fct((ptr)->arg1, (ptr)->arg2, (ptr)->arg3); \
|
||||||
|
caller_initcall = NULL; \
|
||||||
|
caller_file = NULL; \
|
||||||
|
caller_line = 0; \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif // USE_OBSOLETE_LINKER
|
#endif // USE_OBSOLETE_LINKER
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
enum jwt_alg jwt_parse_alg(const char *alg_str, unsigned int alg_len);
|
enum jwt_alg jwt_parse_alg(const char *alg_str, unsigned int alg_len);
|
||||||
int jwt_tokenize(const struct buffer *jwt, struct jwt_item *items, unsigned int *item_num);
|
int jwt_tokenize(const struct buffer *jwt, struct jwt_item *items, unsigned int item_num);
|
||||||
int jwt_tree_load_cert(char *path, int pathlen, int tryload_cert, const char *file, int line, char **err);
|
int jwt_tree_load_cert(char *path, int pathlen, int tryload_cert, const char *file, int line, char **err);
|
||||||
|
|
||||||
enum jwt_vrfy_status jwt_verify(const struct buffer *token, const struct buffer *alg,
|
enum jwt_vrfy_status jwt_verify(const struct buffer *token, const struct buffer *alg,
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,13 @@
|
||||||
#include <import/ebtree-t.h>
|
#include <import/ebtree-t.h>
|
||||||
|
|
||||||
#include <haproxy/api-t.h>
|
#include <haproxy/api-t.h>
|
||||||
|
#include <haproxy/counters-t.h>
|
||||||
#include <haproxy/guid-t.h>
|
#include <haproxy/guid-t.h>
|
||||||
#include <haproxy/obj_type-t.h>
|
#include <haproxy/obj_type-t.h>
|
||||||
#include <haproxy/quic_cc-t.h>
|
#include <haproxy/quic_cc-t.h>
|
||||||
#include <haproxy/quic_sock-t.h>
|
#include <haproxy/quic_sock-t.h>
|
||||||
#include <haproxy/quic_tp-t.h>
|
#include <haproxy/quic_tp-t.h>
|
||||||
#include <haproxy/receiver-t.h>
|
#include <haproxy/receiver-t.h>
|
||||||
#include <haproxy/stats-t.h>
|
|
||||||
#include <haproxy/thread.h>
|
#include <haproxy/thread.h>
|
||||||
|
|
||||||
/* Some pointer types reference below */
|
/* Some pointer types reference below */
|
||||||
|
|
@ -263,6 +263,7 @@ struct listener {
|
||||||
|
|
||||||
struct li_per_thread *per_thr; /* per-thread fields (one per thread in the group) */
|
struct li_per_thread *per_thr; /* per-thread fields (one per thread in the group) */
|
||||||
|
|
||||||
|
char *extra_counters_storage; /* storage for extra_counters */
|
||||||
EXTRA_COUNTERS(extra_counters);
|
EXTRA_COUNTERS(extra_counters);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,8 @@ enum qcc_app_ops_close_side {
|
||||||
|
|
||||||
/* QUIC application layer operations */
|
/* QUIC application layer operations */
|
||||||
struct qcc_app_ops {
|
struct qcc_app_ops {
|
||||||
|
const char *alpn;
|
||||||
|
|
||||||
/* Initialize <qcc> connection app context. */
|
/* Initialize <qcc> connection app context. */
|
||||||
int (*init)(struct qcc *qcc);
|
int (*init)(struct qcc *qcc);
|
||||||
/* Finish connection initialization if prelude required. */
|
/* Finish connection initialization if prelude required. */
|
||||||
|
|
@ -232,6 +234,9 @@ struct qcc_app_ops {
|
||||||
void (*inc_err_cnt)(void *ctx, int err_code);
|
void (*inc_err_cnt)(void *ctx, int err_code);
|
||||||
/* Set QCC error code as suspicious activity has been detected. */
|
/* Set QCC error code as suspicious activity has been detected. */
|
||||||
void (*report_susp)(void *ctx);
|
void (*report_susp)(void *ctx);
|
||||||
|
|
||||||
|
/* Free function to close a stream after MUX layer shutdown. */
|
||||||
|
int (*strm_reject)(struct list *out, uint64_t id);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* USE_QUIC */
|
#endif /* USE_QUIC */
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@
|
||||||
#include <haproxy/mux_quic-t.h>
|
#include <haproxy/mux_quic-t.h>
|
||||||
#include <haproxy/stconn.h>
|
#include <haproxy/stconn.h>
|
||||||
|
|
||||||
|
#include <haproxy/h3.h>
|
||||||
|
#include <haproxy/hq_interop.h>
|
||||||
|
|
||||||
#define qcc_report_glitch(qcc, inc, ...) ({ \
|
#define qcc_report_glitch(qcc, inc, ...) ({ \
|
||||||
COUNT_GLITCH(__VA_ARGS__); \
|
COUNT_GLITCH(__VA_ARGS__); \
|
||||||
_qcc_report_glitch(qcc, inc); \
|
_qcc_report_glitch(qcc, inc); \
|
||||||
|
|
@ -88,7 +91,7 @@ static inline char *qcs_st_to_str(enum qcs_state st)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int qcc_install_app_ops(struct qcc *qcc, const struct qcc_app_ops *app_ops);
|
int qcc_install_app_ops(struct qcc *qcc);
|
||||||
|
|
||||||
/* Register <qcs> stream for http-request timeout. If the stream is not yet
|
/* Register <qcs> stream for http-request timeout. If the stream is not yet
|
||||||
* attached in the configured delay, qcc timeout task will be triggered. This
|
* attached in the configured delay, qcc timeout task will be triggered. This
|
||||||
|
|
@ -115,6 +118,16 @@ void qcc_show_quic(struct qcc *qcc);
|
||||||
|
|
||||||
void qcc_wakeup(struct qcc *qcc);
|
void qcc_wakeup(struct qcc *qcc);
|
||||||
|
|
||||||
|
static inline const struct qcc_app_ops *quic_alpn_to_app_ops(const char *alpn, int alpn_len)
|
||||||
|
{
|
||||||
|
if (alpn_len >= 2 && memcmp(alpn, "h3", 2) == 0)
|
||||||
|
return &h3_ops;
|
||||||
|
else if (alpn_len >= 10 && memcmp(alpn, "hq-interop", 10) == 0)
|
||||||
|
return &hq_interop_ops;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* USE_QUIC */
|
#endif /* USE_QUIC */
|
||||||
|
|
||||||
#endif /* _HAPROXY_MUX_QUIC_H */
|
#endif /* _HAPROXY_MUX_QUIC_H */
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,12 @@ static inline unsigned long ERR_peek_error_func(const char **func)
|
||||||
#define __OPENSSL_110_CONST__
|
#define __OPENSSL_110_CONST__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x40000000L) && (!defined(USE_OPENSSL_WOLFSSL))
|
||||||
|
#define __X509_NAME_CONST__ const
|
||||||
|
#else
|
||||||
|
#define __X509_NAME_CONST__
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ERR_remove_state() was deprecated in 1.0.0 in favor of
|
/* ERR_remove_state() was deprecated in 1.0.0 in favor of
|
||||||
* ERR_remove_thread_state(), which was in turn deprecated in
|
* ERR_remove_thread_state(), which was in turn deprecated in
|
||||||
* 1.1.0 and does nothing anymore. Let's simply silently kill
|
* 1.1.0 and does nothing anymore. Let's simply silently kill
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,12 @@ static inline int real_family(int ss_family)
|
||||||
return fam ? fam->real_family : AF_UNSPEC;
|
return fam ? fam->real_family : AF_UNSPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int proto_is_quic(const struct protocol *proto)
|
||||||
|
{
|
||||||
|
return (proto->proto_type == PROTO_TYPE_DGRAM &&
|
||||||
|
proto->xprt_type == PROTO_TYPE_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _HAPROXY_PROTOCOL_H */
|
#endif /* _HAPROXY_PROTOCOL_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@
|
||||||
#include <haproxy/obj_type-t.h>
|
#include <haproxy/obj_type-t.h>
|
||||||
#include <haproxy/queue-t.h>
|
#include <haproxy/queue-t.h>
|
||||||
#include <haproxy/server-t.h>
|
#include <haproxy/server-t.h>
|
||||||
#include <haproxy/stats-t.h>
|
|
||||||
#include <haproxy/tcpcheck-t.h>
|
#include <haproxy/tcpcheck-t.h>
|
||||||
#include <haproxy/thread-t.h>
|
#include <haproxy/thread-t.h>
|
||||||
#include <haproxy/tools-t.h>
|
#include <haproxy/tools-t.h>
|
||||||
|
|
@ -157,14 +156,17 @@ enum PR_SRV_STATE_FILE {
|
||||||
#define PR_O2_RSTRICT_REQ_HDR_NAMES_NOOP 0x01000000 /* preserve request header names containing chars outside of [0-9a-zA-Z-] charset */
|
#define PR_O2_RSTRICT_REQ_HDR_NAMES_NOOP 0x01000000 /* preserve request header names containing chars outside of [0-9a-zA-Z-] charset */
|
||||||
#define PR_O2_RSTRICT_REQ_HDR_NAMES_MASK 0x01c00000 /* mask for restrict-http-header-names option */
|
#define PR_O2_RSTRICT_REQ_HDR_NAMES_MASK 0x01c00000 /* mask for restrict-http-header-names option */
|
||||||
|
|
||||||
/* unused : 0x02000000 ... 0x08000000 */
|
|
||||||
|
|
||||||
/* server health checks */
|
/* server health checks */
|
||||||
#define PR_O2_CHK_NONE 0x00000000 /* no L7 health checks configured (TCP by default) */
|
#define PR_O2_CHK_NONE 0x00000000 /* no L7 health checks configured (TCP by default) */
|
||||||
#define PR_O2_TCPCHK_CHK 0x90000000 /* use TCPCHK check for server health */
|
#define PR_O2_TCPCHK_CHK 0x02000000 /* use TCPCHK check for server health */
|
||||||
#define PR_O2_EXT_CHK 0xA0000000 /* use external command for server health */
|
#define PR_O2_EXT_CHK 0x04000000 /* use external command for server health */
|
||||||
/* unused: 0xB0000000 to 0xF000000, reserved for health checks */
|
#define PR_O2_CHK_ANY 0x06000000 /* Mask to cover any check */
|
||||||
#define PR_O2_CHK_ANY 0xF0000000 /* Mask to cover any check */
|
|
||||||
|
#define PR_O2_USE_SBUF_QUEUE 0x08000000 /* use small buffer for request when stream are queued*/
|
||||||
|
#define PR_O2_USE_SBUF_L7_RETRY 0x10000000 /* use small buffer for request when L7 retires are enabled */
|
||||||
|
#define PR_O2_USE_SBUF_CHECK 0x20000000 /* use small buffer for request's healthchecks */
|
||||||
|
#define PR_O2_USE_SBUF_ALL 0x38000000 /* all flags for use-large-buffer option */
|
||||||
|
/* unused : 0x40000000 ... 0x80000000 */
|
||||||
/* end of proxy->options2 */
|
/* end of proxy->options2 */
|
||||||
|
|
||||||
/* bits for proxy->options3 */
|
/* bits for proxy->options3 */
|
||||||
|
|
@ -240,14 +242,16 @@ enum PR_SRV_STATE_FILE {
|
||||||
#define PR_RE_JUNK_REQUEST 0x00020000 /* We received an incomplete or garbage response */
|
#define PR_RE_JUNK_REQUEST 0x00020000 /* We received an incomplete or garbage response */
|
||||||
|
|
||||||
/* Proxy flags */
|
/* Proxy flags */
|
||||||
#define PR_FL_DISABLED 0x01 /* The proxy was disabled in the configuration (not at runtime) */
|
#define PR_FL_DISABLED 0x00000001 /* The proxy was disabled in the configuration (not at runtime) */
|
||||||
#define PR_FL_STOPPED 0x02 /* The proxy was stopped */
|
#define PR_FL_STOPPED 0x00000002 /* The proxy was stopped */
|
||||||
#define PR_FL_DEF_EXPLICIT_MODE 0x04 /* Proxy mode is explicitely defined - only used for defaults instance */
|
#define PR_FL_DEF_EXPLICIT_MODE 0x00000004 /* Proxy mode is explicitely defined - only used for defaults instance */
|
||||||
#define PR_FL_EXPLICIT_REF 0x08 /* The default proxy is explicitly referenced by another proxy */
|
#define PR_FL_EXPLICIT_REF 0x00000008 /* The default proxy is explicitly referenced by another proxy */
|
||||||
#define PR_FL_IMPLICIT_REF 0x10 /* The default proxy is implicitly referenced by another proxy */
|
#define PR_FL_IMPLICIT_REF 0x00000010 /* The default proxy is implicitly referenced by another proxy */
|
||||||
#define PR_FL_PAUSED 0x20 /* The proxy was paused at run time (reversible) */
|
#define PR_FL_PAUSED 0x00000020 /* The proxy was paused at run time (reversible) */
|
||||||
#define PR_FL_CHECKED 0x40 /* The proxy configuration was fully checked (including postparsing checks) */
|
#define PR_FL_CHECKED 0x00000040 /* The proxy configuration was fully checked (including postparsing checks) */
|
||||||
#define PR_FL_BE_UNPUBLISHED 0x80 /* The proxy cannot be targetted by content switching rules */
|
#define PR_FL_BE_UNPUBLISHED 0x00000080 /* The proxy cannot be targetted by content switching rules */
|
||||||
|
#define PR_FL_DELETED 0x00000100 /* Proxy has been deleted and must be manipulated with care */
|
||||||
|
#define PR_FL_NON_PURGEABLE 0x00000200 /* Proxy referenced by config elements which prevent its runtime removal. */
|
||||||
|
|
||||||
struct stream;
|
struct stream;
|
||||||
|
|
||||||
|
|
@ -306,13 +310,16 @@ struct error_snapshot {
|
||||||
struct proxy_per_tgroup {
|
struct proxy_per_tgroup {
|
||||||
struct queue queue;
|
struct queue queue;
|
||||||
struct lbprm_per_tgrp lbprm;
|
struct lbprm_per_tgrp lbprm;
|
||||||
|
char *extra_counters_fe_storage; /* storage for extra_counters_fe */
|
||||||
|
char *extra_counters_be_storage; /* storage for extra_counters_be */
|
||||||
} THREAD_ALIGNED();
|
} THREAD_ALIGNED();
|
||||||
|
|
||||||
struct proxy {
|
struct proxy {
|
||||||
enum obj_type obj_type; /* object type == OBJ_TYPE_PROXY */
|
enum obj_type obj_type; /* object type == OBJ_TYPE_PROXY */
|
||||||
char flags; /* bit field PR_FL_* */
|
|
||||||
enum pr_mode mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP, ... */
|
enum pr_mode mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP, ... */
|
||||||
char cap; /* supported capabilities (PR_CAP_*) */
|
char cap; /* supported capabilities (PR_CAP_*) */
|
||||||
|
/* 1 byte hole */
|
||||||
|
unsigned int flags; /* bit field PR_FL_* */
|
||||||
int to_log; /* things to be logged (LW_*), special value LW_LOGSTEPS == follow log-steps */
|
int to_log; /* things to be logged (LW_*), special value LW_LOGSTEPS == follow log-steps */
|
||||||
unsigned long last_change; /* internal use only: last time the proxy state was changed */
|
unsigned long last_change; /* internal use only: last time the proxy state was changed */
|
||||||
|
|
||||||
|
|
@ -476,7 +483,7 @@ struct proxy {
|
||||||
struct log_steps log_steps; /* bitfield of log origins where log should be generated during request handling */
|
struct log_steps log_steps; /* bitfield of log origins where log should be generated during request handling */
|
||||||
const char *file_prev; /* file of the previous instance found with the same name, or NULL */
|
const char *file_prev; /* file of the previous instance found with the same name, or NULL */
|
||||||
int line_prev; /* line of the previous instance found with the same name, or 0 */
|
int line_prev; /* line of the previous instance found with the same name, or 0 */
|
||||||
unsigned int refcount; /* refcount on this proxy (only used for default proxy for now) */
|
unsigned int def_ref; /* default proxy only refcount */
|
||||||
} conf; /* config information */
|
} conf; /* config information */
|
||||||
struct http_ext *http_ext; /* http ext options */
|
struct http_ext *http_ext; /* http ext options */
|
||||||
struct ceb_root *used_server_addr; /* list of server addresses in use */
|
struct ceb_root *used_server_addr; /* list of server addresses in use */
|
||||||
|
|
@ -505,6 +512,8 @@ struct proxy {
|
||||||
struct list filter_configs; /* list of the filters that are declared on this proxy */
|
struct list filter_configs; /* list of the filters that are declared on this proxy */
|
||||||
|
|
||||||
struct guid_node guid; /* GUID global tree node */
|
struct guid_node guid; /* GUID global tree node */
|
||||||
|
struct mt_list watcher_list; /* list of elems which currently references this proxy instance (currently only used with backends) */
|
||||||
|
uint refcount; /* refcount to keep proxy from being deleted during runtime */
|
||||||
|
|
||||||
EXTRA_COUNTERS(extra_counters_fe);
|
EXTRA_COUNTERS(extra_counters_fe);
|
||||||
EXTRA_COUNTERS(extra_counters_be);
|
EXTRA_COUNTERS(extra_counters_be);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <haproxy/api.h>
|
#include <haproxy/api.h>
|
||||||
#include <haproxy/applet-t.h>
|
#include <haproxy/applet-t.h>
|
||||||
|
#include <haproxy/counters.h>
|
||||||
#include <haproxy/freq_ctr.h>
|
#include <haproxy/freq_ctr.h>
|
||||||
#include <haproxy/list.h>
|
#include <haproxy/list.h>
|
||||||
#include <haproxy/listener-t.h>
|
#include <haproxy/listener-t.h>
|
||||||
|
|
@ -58,7 +59,7 @@ void stop_proxy(struct proxy *p);
|
||||||
int stream_set_backend(struct stream *s, struct proxy *be);
|
int stream_set_backend(struct stream *s, struct proxy *be);
|
||||||
|
|
||||||
void deinit_proxy(struct proxy *p);
|
void deinit_proxy(struct proxy *p);
|
||||||
void free_proxy(struct proxy *p);
|
void proxy_drop(struct proxy *p);
|
||||||
const char *proxy_cap_str(int cap);
|
const char *proxy_cap_str(int cap);
|
||||||
const char *proxy_mode_str(int mode);
|
const char *proxy_mode_str(int mode);
|
||||||
enum pr_mode str_to_proxy_mode(const char *mode);
|
enum pr_mode str_to_proxy_mode(const char *mode);
|
||||||
|
|
@ -82,6 +83,7 @@ void proxy_unref_defaults(struct proxy *px);
|
||||||
int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg);
|
int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg);
|
||||||
struct proxy *alloc_new_proxy(const char *name, unsigned int cap,
|
struct proxy *alloc_new_proxy(const char *name, unsigned int cap,
|
||||||
char **errmsg);
|
char **errmsg);
|
||||||
|
void proxy_take(struct proxy *px);
|
||||||
struct proxy *parse_new_proxy(const char *name, unsigned int cap,
|
struct proxy *parse_new_proxy(const char *name, unsigned int cap,
|
||||||
const char *file, int linenum,
|
const char *file, int linenum,
|
||||||
const struct proxy *defproxy);
|
const struct proxy *defproxy);
|
||||||
|
|
@ -101,6 +103,8 @@ void free_server_rules(struct list *srules);
|
||||||
int proxy_init_per_thr(struct proxy *px);
|
int proxy_init_per_thr(struct proxy *px);
|
||||||
int proxy_finalize(struct proxy *px, int *err_code);
|
int proxy_finalize(struct proxy *px, int *err_code);
|
||||||
|
|
||||||
|
int be_check_for_deletion(const char *bename, struct proxy **pb, const char **pm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function returns a string containing the type of the proxy in a format
|
* This function returns a string containing the type of the proxy in a format
|
||||||
* suitable for error messages, from its capabilities.
|
* suitable for error messages, from its capabilities.
|
||||||
|
|
@ -178,7 +182,7 @@ static inline void proxy_inc_fe_conn_ctr(struct listener *l, struct proxy *fe)
|
||||||
}
|
}
|
||||||
if (l && l->counters && l->counters->shared.tg)
|
if (l && l->counters && l->counters->shared.tg)
|
||||||
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_conn);
|
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_conn);
|
||||||
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.cps_max,
|
COUNTERS_UPDATE_MAX(&fe->fe_counters.cps_max,
|
||||||
update_freq_ctr(&fe->fe_counters._conn_per_sec, 1));
|
update_freq_ctr(&fe->fe_counters._conn_per_sec, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,7 +195,7 @@ static inline void proxy_inc_fe_sess_ctr(struct listener *l, struct proxy *fe)
|
||||||
}
|
}
|
||||||
if (l && l->counters && l->counters->shared.tg)
|
if (l && l->counters && l->counters->shared.tg)
|
||||||
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_sess);
|
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->cum_sess);
|
||||||
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.sps_max,
|
COUNTERS_UPDATE_MAX(&fe->fe_counters.sps_max,
|
||||||
update_freq_ctr(&fe->fe_counters._sess_per_sec, 1));
|
update_freq_ctr(&fe->fe_counters._sess_per_sec, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,7 +222,7 @@ static inline void proxy_inc_be_ctr(struct proxy *be)
|
||||||
_HA_ATOMIC_INC(&be->be_counters.shared.tg[tgid - 1]->cum_sess);
|
_HA_ATOMIC_INC(&be->be_counters.shared.tg[tgid - 1]->cum_sess);
|
||||||
update_freq_ctr(&be->be_counters.shared.tg[tgid - 1]->sess_per_sec, 1);
|
update_freq_ctr(&be->be_counters.shared.tg[tgid - 1]->sess_per_sec, 1);
|
||||||
}
|
}
|
||||||
HA_ATOMIC_UPDATE_MAX(&be->be_counters.sps_max,
|
COUNTERS_UPDATE_MAX(&be->be_counters.sps_max,
|
||||||
update_freq_ctr(&be->be_counters._sess_per_sec, 1));
|
update_freq_ctr(&be->be_counters._sess_per_sec, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,7 +242,7 @@ static inline void proxy_inc_fe_req_ctr(struct listener *l, struct proxy *fe,
|
||||||
}
|
}
|
||||||
if (l && l->counters && l->counters->shared.tg)
|
if (l && l->counters && l->counters->shared.tg)
|
||||||
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->p.http.cum_req[http_ver]);
|
_HA_ATOMIC_INC(&l->counters->shared.tg[tgid - 1]->p.http.cum_req[http_ver]);
|
||||||
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.p.http.rps_max,
|
COUNTERS_UPDATE_MAX(&fe->fe_counters.p.http.rps_max,
|
||||||
update_freq_ctr(&fe->fe_counters.p.http._req_per_sec, 1));
|
update_freq_ctr(&fe->fe_counters.p.http._req_per_sec, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@
|
||||||
#include <haproxy/quic_cc-t.h>
|
#include <haproxy/quic_cc-t.h>
|
||||||
#include <haproxy/quic_frame-t.h>
|
#include <haproxy/quic_frame-t.h>
|
||||||
#include <haproxy/quic_openssl_compat-t.h>
|
#include <haproxy/quic_openssl_compat-t.h>
|
||||||
#include <haproxy/quic_stats-t.h>
|
|
||||||
#include <haproxy/quic_tls-t.h>
|
#include <haproxy/quic_tls-t.h>
|
||||||
#include <haproxy/quic_tp-t.h>
|
#include <haproxy/quic_tp-t.h>
|
||||||
#include <haproxy/show_flags-t.h>
|
#include <haproxy/show_flags-t.h>
|
||||||
|
|
@ -401,6 +400,8 @@ struct quic_conn {
|
||||||
|
|
||||||
struct eb_root streams_by_id; /* qc_stream_desc tree */
|
struct eb_root streams_by_id; /* qc_stream_desc tree */
|
||||||
|
|
||||||
|
const char *alpn;
|
||||||
|
|
||||||
/* MUX */
|
/* MUX */
|
||||||
struct qcc *qcc;
|
struct qcc *qcc;
|
||||||
struct task *timer_task;
|
struct task *timer_task;
|
||||||
|
|
@ -409,7 +410,9 @@ struct quic_conn {
|
||||||
/* Handshake expiration date */
|
/* Handshake expiration date */
|
||||||
unsigned int hs_expire;
|
unsigned int hs_expire;
|
||||||
|
|
||||||
const struct qcc_app_ops *app_ops;
|
/* Callback to close any stream after MUX closure - set by the MUX itself */
|
||||||
|
int (*strm_reject)(struct list *out, uint64_t stream_id);
|
||||||
|
|
||||||
/* Proxy counters */
|
/* Proxy counters */
|
||||||
struct quic_counters *prx_counters;
|
struct quic_counters *prx_counters;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include <import/eb64tree.h>
|
#include <import/eb64tree.h>
|
||||||
#include <import/ebmbtree.h>
|
#include <import/ebmbtree.h>
|
||||||
|
|
||||||
|
#include <haproxy/counters.h>
|
||||||
#include <haproxy/chunk.h>
|
#include <haproxy/chunk.h>
|
||||||
#include <haproxy/dynbuf.h>
|
#include <haproxy/dynbuf.h>
|
||||||
#include <haproxy/ncbmbuf.h>
|
#include <haproxy/ncbmbuf.h>
|
||||||
|
|
@ -83,7 +84,7 @@ void qc_check_close_on_released_mux(struct quic_conn *qc);
|
||||||
int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len,
|
int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len,
|
||||||
const unsigned char *salt, size_t saltlen);
|
const unsigned char *salt, size_t saltlen);
|
||||||
int quic_reuse_srv_params(struct quic_conn *qc,
|
int quic_reuse_srv_params(struct quic_conn *qc,
|
||||||
const unsigned char *alpn,
|
const char *alpn,
|
||||||
const struct quic_early_transport_params *etps);
|
const struct quic_early_transport_params *etps);
|
||||||
|
|
||||||
/* Returns true if <qc> is used on the backed side (as a client). */
|
/* Returns true if <qc> is used on the backed side (as a client). */
|
||||||
|
|
@ -193,13 +194,17 @@ static inline void *qc_counters(enum obj_type *o, const struct stats_module *m)
|
||||||
p = l ? l->bind_conf->frontend :
|
p = l ? l->bind_conf->frontend :
|
||||||
s ? s->proxy : NULL;
|
s ? s->proxy : NULL;
|
||||||
|
|
||||||
return p ? EXTRA_COUNTERS_GET(p->extra_counters_fe, m) : NULL;
|
if (l && p)
|
||||||
|
return EXTRA_COUNTERS_GET(p->extra_counters_fe, m);
|
||||||
|
else if (s && p)
|
||||||
|
return EXTRA_COUNTERS_GET(p->extra_counters_be, m);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
|
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
|
||||||
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
|
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
|
||||||
void quic_set_tls_alert(struct quic_conn *qc, int alert);
|
void quic_set_tls_alert(struct quic_conn *qc, int alert);
|
||||||
int quic_set_app_ops(struct quic_conn *qc, const unsigned char *alpn, size_t alpn_len);
|
int qc_register_alpn(struct quic_conn *qc, const char *alpn, int alpn_len);
|
||||||
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len);
|
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len);
|
||||||
|
|
||||||
void qc_notify_err(struct quic_conn *qc);
|
void qc_notify_err(struct quic_conn *qc);
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
#error "Must define USE_OPENSSL"
|
#error "Must define USE_OPENSSL"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct stats_module quic_stats_module;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
QUIC_ST_RXBUF_FULL,
|
QUIC_ST_RXBUF_FULL,
|
||||||
QUIC_ST_DROPPED_PACKET,
|
QUIC_ST_DROPPED_PACKET,
|
||||||
|
|
@ -52,6 +50,7 @@ enum {
|
||||||
QUIC_ST_STREAM_DATA_BLOCKED,
|
QUIC_ST_STREAM_DATA_BLOCKED,
|
||||||
QUIC_ST_STREAMS_BLOCKED_BIDI,
|
QUIC_ST_STREAMS_BLOCKED_BIDI,
|
||||||
QUIC_ST_STREAMS_BLOCKED_UNI,
|
QUIC_ST_STREAMS_BLOCKED_UNI,
|
||||||
|
QUIC_ST_NCBUF_GAP_LIMIT,
|
||||||
QUIC_STATS_COUNT /* must be the last */
|
QUIC_STATS_COUNT /* must be the last */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -99,6 +98,7 @@ struct quic_counters {
|
||||||
long long stream_data_blocked; /* total number of times STREAM_DATA_BLOCKED frame was received */
|
long long stream_data_blocked; /* total number of times STREAM_DATA_BLOCKED frame was received */
|
||||||
long long streams_blocked_bidi; /* total number of times STREAMS_BLOCKED_BIDI frame was received */
|
long long streams_blocked_bidi; /* total number of times STREAMS_BLOCKED_BIDI frame was received */
|
||||||
long long streams_blocked_uni; /* total number of times STREAMS_BLOCKED_UNI frame was received */
|
long long streams_blocked_uni; /* total number of times STREAMS_BLOCKED_UNI frame was received */
|
||||||
|
long long ncbuf_gap_limit; /* total number of times we failed to add data to ncbuf due to gap size limit */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* USE_QUIC */
|
#endif /* USE_QUIC */
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <haproxy/quic_stats-t.h>
|
#include <haproxy/quic_stats-t.h>
|
||||||
|
#include <haproxy/stats-t.h>
|
||||||
|
|
||||||
|
extern struct stats_module quic_stats_module;
|
||||||
void quic_stats_transp_err_count_inc(struct quic_counters *ctrs, int error_code);
|
void quic_stats_transp_err_count_inc(struct quic_counters *ctrs, int error_code);
|
||||||
|
|
||||||
#endif /* USE_QUIC */
|
#endif /* USE_QUIC */
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
#include <haproxy/connection-t.h>
|
#include <haproxy/connection-t.h>
|
||||||
#include <haproxy/dns-t.h>
|
#include <haproxy/dns-t.h>
|
||||||
#include <haproxy/obj_type-t.h>
|
#include <haproxy/obj_type-t.h>
|
||||||
#include <haproxy/stats-t.h>
|
|
||||||
#include <haproxy/task-t.h>
|
#include <haproxy/task-t.h>
|
||||||
#include <haproxy/thread.h>
|
#include <haproxy/thread.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#define _HAPROXY_SAMPLE_T_H
|
#define _HAPROXY_SAMPLE_T_H
|
||||||
|
|
||||||
#include <haproxy/api-t.h>
|
#include <haproxy/api-t.h>
|
||||||
|
#include <haproxy/tinfo-t.h>
|
||||||
#include <haproxy/sample_data-t.h>
|
#include <haproxy/sample_data-t.h>
|
||||||
|
|
||||||
/* input and output sample types
|
/* input and output sample types
|
||||||
|
|
@ -265,6 +266,7 @@ struct sample_conv {
|
||||||
unsigned int in_type; /* expected input sample type */
|
unsigned int in_type; /* expected input sample type */
|
||||||
unsigned int out_type; /* output sample type */
|
unsigned int out_type; /* output sample type */
|
||||||
void *private; /* private values. only used by maps and Lua */
|
void *private; /* private values. only used by maps and Lua */
|
||||||
|
struct thread_exec_ctx exec_ctx; /* execution context */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* sample conversion expression */
|
/* sample conversion expression */
|
||||||
|
|
@ -288,6 +290,7 @@ struct sample_fetch {
|
||||||
unsigned int use; /* fetch source (SMP_USE_*) */
|
unsigned int use; /* fetch source (SMP_USE_*) */
|
||||||
unsigned int val; /* fetch validity (SMP_VAL_*) */
|
unsigned int val; /* fetch validity (SMP_VAL_*) */
|
||||||
void *private; /* private values. only used by Lua */
|
void *private; /* private values. only used by Lua */
|
||||||
|
struct thread_exec_ctx exec_ctx; /* execution context */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* sample expression */
|
/* sample expression */
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,10 @@
|
||||||
void sc_update_rx(struct stconn *sc);
|
void sc_update_rx(struct stconn *sc);
|
||||||
void sc_update_tx(struct stconn *sc);
|
void sc_update_tx(struct stconn *sc);
|
||||||
|
|
||||||
|
void sc_abort(struct stconn *sc);
|
||||||
|
void sc_shutdown(struct stconn *sc);
|
||||||
|
void sc_chk_rcv(struct stconn *sc);
|
||||||
|
|
||||||
struct task *sc_conn_io_cb(struct task *t, void *ctx, unsigned int state);
|
struct task *sc_conn_io_cb(struct task *t, void *ctx, unsigned int state);
|
||||||
int sc_conn_sync_recv(struct stconn *sc);
|
int sc_conn_sync_recv(struct stconn *sc);
|
||||||
int sc_conn_sync_send(struct stconn *sc);
|
int sc_conn_sync_send(struct stconn *sc);
|
||||||
|
|
@ -360,38 +364,6 @@ static inline int sc_is_recv_allowed(const struct stconn *sc)
|
||||||
return !(sc->flags & (SC_FL_WONT_READ|SC_FL_NEED_BUFF|SC_FL_NEED_ROOM));
|
return !(sc->flags & (SC_FL_WONT_READ|SC_FL_NEED_BUFF|SC_FL_NEED_ROOM));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is to be used after making some room available in a channel. It will
|
|
||||||
* return without doing anything if the stream connector's RX path is blocked.
|
|
||||||
* It will automatically mark the stream connector as busy processing the end
|
|
||||||
* point in order to avoid useless repeated wakeups.
|
|
||||||
* It will then call ->chk_rcv() to enable receipt of new data.
|
|
||||||
*/
|
|
||||||
static inline void sc_chk_rcv(struct stconn *sc)
|
|
||||||
{
|
|
||||||
if (sc_ep_test(sc, SE_FL_APPLET_NEED_CONN) &&
|
|
||||||
sc_state_in(sc_opposite(sc)->state, SC_SB_RDY|SC_SB_EST|SC_SB_DIS|SC_SB_CLO)) {
|
|
||||||
sc_ep_clr(sc, SE_FL_APPLET_NEED_CONN);
|
|
||||||
sc_ep_report_read_activity(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sc_is_recv_allowed(sc))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!sc_state_in(sc->state, SC_SB_RDY|SC_SB_EST))
|
|
||||||
return;
|
|
||||||
|
|
||||||
sc_ep_set(sc, SE_FL_HAVE_NO_DATA);
|
|
||||||
if (likely(sc->app_ops->chk_rcv))
|
|
||||||
sc->app_ops->chk_rcv(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calls chk_snd on the endpoint using the data layer */
|
|
||||||
static inline void sc_chk_snd(struct stconn *sc)
|
|
||||||
{
|
|
||||||
if (likely(sc->app_ops->chk_snd))
|
|
||||||
sc->app_ops->chk_snd(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Perform a synchronous receive using the right version, depending the endpoing
|
/* Perform a synchronous receive using the right version, depending the endpoing
|
||||||
* is a connection or an applet.
|
* is a connection or an applet.
|
||||||
|
|
@ -536,24 +508,10 @@ static inline void sc_schedule_abort(struct stconn *sc)
|
||||||
sc->flags |= SC_FL_ABRT_WANTED;
|
sc->flags |= SC_FL_ABRT_WANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Abort the SC and notify the endpoint using the data layer */
|
|
||||||
static inline void sc_abort(struct stconn *sc)
|
|
||||||
{
|
|
||||||
if (likely(sc->app_ops->abort))
|
|
||||||
sc->app_ops->abort(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Schedule a shutdown for the SC */
|
/* Schedule a shutdown for the SC */
|
||||||
static inline void sc_schedule_shutdown(struct stconn *sc)
|
static inline void sc_schedule_shutdown(struct stconn *sc)
|
||||||
{
|
{
|
||||||
sc->flags |= SC_FL_SHUT_WANTED;
|
sc->flags |= SC_FL_SHUT_WANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shutdown the SC and notify the endpoint using the data layer */
|
|
||||||
static inline void sc_shutdown(struct stconn *sc)
|
|
||||||
{
|
|
||||||
if (likely(sc->app_ops->shutdown))
|
|
||||||
sc->app_ops->shutdown(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _HAPROXY_SC_STRM_H */
|
#endif /* _HAPROXY_SC_STRM_H */
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,7 @@ struct srv_per_tgroup {
|
||||||
struct queue queue; /* pending connections */
|
struct queue queue; /* pending connections */
|
||||||
struct server *server; /* pointer to the corresponding server */
|
struct server *server; /* pointer to the corresponding server */
|
||||||
struct eb32_node lb_node; /* node used for tree-based load balancing */
|
struct eb32_node lb_node; /* node used for tree-based load balancing */
|
||||||
|
char *extra_counters_storage; /* storage for extra_counters */
|
||||||
struct server *next_full; /* next server in the temporary full list */
|
struct server *next_full; /* next server in the temporary full list */
|
||||||
unsigned int last_other_tgrp_served; /* Last other tgrp we dequeued from */
|
unsigned int last_other_tgrp_served; /* Last other tgrp we dequeued from */
|
||||||
unsigned int self_served; /* Number of connection we dequeued from our own queue */
|
unsigned int self_served; /* Number of connection we dequeued from our own queue */
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include <haproxy/api.h>
|
#include <haproxy/api.h>
|
||||||
#include <haproxy/applet-t.h>
|
#include <haproxy/applet-t.h>
|
||||||
#include <haproxy/arg-t.h>
|
#include <haproxy/arg-t.h>
|
||||||
|
#include <haproxy/counters.h>
|
||||||
#include <haproxy/freq_ctr.h>
|
#include <haproxy/freq_ctr.h>
|
||||||
#include <haproxy/proxy-t.h>
|
#include <haproxy/proxy-t.h>
|
||||||
#include <haproxy/resolvers-t.h>
|
#include <haproxy/resolvers-t.h>
|
||||||
|
|
@ -55,6 +56,7 @@ int srv_update_addr(struct server *s, void *ip, int ip_sin_family, struct server
|
||||||
struct sample_expr *_parse_srv_expr(char *expr, struct arg_list *args_px,
|
struct sample_expr *_parse_srv_expr(char *expr, struct arg_list *args_px,
|
||||||
const char *file, int linenum, char **err);
|
const char *file, int linenum, char **err);
|
||||||
int server_parse_exprs(struct server *srv, struct proxy *px, char **err);
|
int server_parse_exprs(struct server *srv, struct proxy *px, char **err);
|
||||||
|
int srv_configure_auto_sni(struct server *srv, int *err_code, char **err);
|
||||||
int server_set_inetaddr(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater, struct buffer *msg);
|
int server_set_inetaddr(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater, struct buffer *msg);
|
||||||
int server_set_inetaddr_warn(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater);
|
int server_set_inetaddr_warn(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater);
|
||||||
void server_get_inetaddr(struct server *s, struct server_inetaddr *inetaddr);
|
void server_get_inetaddr(struct server *s, struct server_inetaddr *inetaddr);
|
||||||
|
|
@ -211,7 +213,7 @@ static inline void srv_inc_sess_ctr(struct server *s)
|
||||||
_HA_ATOMIC_INC(&s->counters.shared.tg[tgid - 1]->cum_sess);
|
_HA_ATOMIC_INC(&s->counters.shared.tg[tgid - 1]->cum_sess);
|
||||||
update_freq_ctr(&s->counters.shared.tg[tgid - 1]->sess_per_sec, 1);
|
update_freq_ctr(&s->counters.shared.tg[tgid - 1]->sess_per_sec, 1);
|
||||||
}
|
}
|
||||||
HA_ATOMIC_UPDATE_MAX(&s->counters.sps_max,
|
COUNTERS_UPDATE_MAX(&s->counters.sps_max,
|
||||||
update_freq_ctr(&s->counters._sess_per_sec, 1));
|
update_freq_ctr(&s->counters._sess_per_sec, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -349,28 +351,26 @@ static inline int srv_is_transparent(const struct server *srv)
|
||||||
(srv->flags & SRV_F_MAPPORTS);
|
(srv->flags & SRV_F_MAPPORTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detach server from proxy list. It is supported to call this
|
/* Detach <srv> server from its parent proxy list.
|
||||||
* even if the server is not yet in the list
|
*
|
||||||
* Must be called under thread isolation or when it is safe to assume
|
* Must be called under thread isolation.
|
||||||
* that the parent proxy doesn't is not skimming through the server list
|
|
||||||
*/
|
*/
|
||||||
static inline void srv_detach(struct server *srv)
|
static inline void srv_detach(struct server *srv)
|
||||||
{
|
{
|
||||||
struct proxy *px = srv->proxy;
|
struct proxy *px = srv->proxy;
|
||||||
|
|
||||||
if (px->srv == srv)
|
|
||||||
px->srv = srv->next;
|
|
||||||
else {
|
|
||||||
struct server *prev;
|
struct server *prev;
|
||||||
|
|
||||||
|
if (px->srv == srv) {
|
||||||
|
px->srv = srv->next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
for (prev = px->srv; prev && prev->next != srv; prev = prev->next)
|
for (prev = px->srv; prev && prev->next != srv; prev = prev->next)
|
||||||
;
|
;
|
||||||
|
BUG_ON(!prev); /* Server instance not found in proxy list ? */
|
||||||
BUG_ON(!prev);
|
|
||||||
|
|
||||||
prev->next = srv->next;
|
prev->next = srv->next;
|
||||||
}
|
}
|
||||||
/* reset the proxy's ready_srv if it was this one */
|
|
||||||
|
/* Reset the proxy's ready_srv if it was this one. */
|
||||||
HA_ATOMIC_CAS(&px->ready_srv, &srv, NULL);
|
HA_ATOMIC_CAS(&px->ready_srv, &srv, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,13 @@
|
||||||
|
|
||||||
|
|
||||||
#include <haproxy/connection.h>
|
#include <haproxy/connection.h>
|
||||||
|
#include <haproxy/counters.h>
|
||||||
#include <haproxy/openssl-compat.h>
|
#include <haproxy/openssl-compat.h>
|
||||||
#include <haproxy/pool-t.h>
|
#include <haproxy/pool-t.h>
|
||||||
#include <haproxy/proxy-t.h>
|
#include <haproxy/proxy-t.h>
|
||||||
#include <haproxy/quic_conn-t.h>
|
#include <haproxy/quic_conn-t.h>
|
||||||
#include <haproxy/ssl_sock-t.h>
|
#include <haproxy/ssl_sock-t.h>
|
||||||
#include <haproxy/stats.h>
|
#include <haproxy/stats-t.h>
|
||||||
#include <haproxy/thread.h>
|
#include <haproxy/thread.h>
|
||||||
|
|
||||||
extern struct list tlskeys_reference;
|
extern struct list tlskeys_reference;
|
||||||
|
|
@ -73,7 +74,7 @@ int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx,
|
||||||
const char **str, int *len);
|
const char **str, int *len);
|
||||||
int ssl_bio_and_sess_init(struct connection *conn, SSL_CTX *ssl_ctx,
|
int ssl_bio_and_sess_init(struct connection *conn, SSL_CTX *ssl_ctx,
|
||||||
SSL **ssl, BIO **bio, BIO_METHOD *bio_meth, void *ctx);
|
SSL **ssl, BIO **bio, BIO_METHOD *bio_meth, void *ctx);
|
||||||
int ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv);
|
void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv);
|
||||||
const char *ssl_sock_get_sni(struct connection *conn);
|
const char *ssl_sock_get_sni(struct connection *conn);
|
||||||
const char *ssl_sock_get_cert_sig(struct connection *conn);
|
const char *ssl_sock_get_cert_sig(struct connection *conn);
|
||||||
const char *ssl_sock_get_cipher_name(struct connection *conn);
|
const char *ssl_sock_get_cipher_name(struct connection *conn);
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ int cert_get_pkey_algo(X509 *crt, struct buffer *out);
|
||||||
int ssl_sock_get_serial(X509 *crt, struct buffer *out);
|
int ssl_sock_get_serial(X509 *crt, struct buffer *out);
|
||||||
int ssl_sock_crt2der(X509 *crt, struct buffer *out);
|
int ssl_sock_crt2der(X509 *crt, struct buffer *out);
|
||||||
int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out);
|
int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out);
|
||||||
int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
|
int ssl_sock_get_dn_entry(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *entry, int pos,
|
||||||
struct buffer *out);
|
struct buffer *out);
|
||||||
int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out);
|
int ssl_sock_get_dn_formatted(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *format, struct buffer *out);
|
||||||
int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out);
|
int ssl_sock_get_dn_oneline(__X509_NAME_CONST__ X509_NAME *a, struct buffer *out);
|
||||||
X509* ssl_sock_get_peer_certificate(SSL *ssl);
|
X509* ssl_sock_get_peer_certificate(SSL *ssl);
|
||||||
X509* ssl_sock_get_verified_chain_root(SSL *ssl);
|
X509* ssl_sock_get_verified_chain_root(SSL *ssl);
|
||||||
unsigned int openssl_version_parser(const char *version);
|
unsigned int openssl_version_parser(const char *version);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ struct shm_stats_file_hdr {
|
||||||
/* 2 bytes hole */
|
/* 2 bytes hole */
|
||||||
uint global_now_ms; /* global monotonic date (ms) common to all processes using the shm */
|
uint global_now_ms; /* global monotonic date (ms) common to all processes using the shm */
|
||||||
ullong global_now_ns; /* global monotonic date (ns) common to all processes using the shm */
|
ullong global_now_ns; /* global monotonic date (ns) common to all processes using the shm */
|
||||||
llong now_offset; /* offset applied to global monotonic date on startup */
|
ALWAYS_PAD(8); // 8 bytes hole
|
||||||
/* each process uses one slot and is identified using its pid, max 64 in order
|
/* each process uses one slot and is identified using its pid, max 64 in order
|
||||||
* to be able to use bitmask to refer to a process and then look its pid in the
|
* to be able to use bitmask to refer to a process and then look its pid in the
|
||||||
* "slots.pid" map
|
* "slots.pid" map
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <import/ebtree-t.h>
|
#include <import/ebtree-t.h>
|
||||||
#include <haproxy/api-t.h>
|
#include <haproxy/api-t.h>
|
||||||
#include <haproxy/buf-t.h>
|
#include <haproxy/buf-t.h>
|
||||||
|
#include <haproxy/counters-t.h>
|
||||||
|
|
||||||
/* Flags for applet.ctx.stats.flags */
|
/* Flags for applet.ctx.stats.flags */
|
||||||
#define STAT_F_FMT_HTML 0x00000001 /* dump the stats in HTML format */
|
#define STAT_F_FMT_HTML 0x00000001 /* dump the stats in HTML format */
|
||||||
|
|
@ -515,23 +516,13 @@ struct field {
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum counters_type {
|
|
||||||
COUNTERS_FE = 0,
|
|
||||||
COUNTERS_BE,
|
|
||||||
COUNTERS_SV,
|
|
||||||
COUNTERS_LI,
|
|
||||||
COUNTERS_RSLV,
|
|
||||||
|
|
||||||
COUNTERS_OFF_END
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Entity used to generate statistics on an HAProxy component */
|
/* Entity used to generate statistics on an HAProxy component */
|
||||||
struct stats_module {
|
struct stats_module {
|
||||||
struct list list;
|
struct list list;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
/* functor used to generate the stats module using counters provided through data parameter */
|
/* function used to generate the stats module using counters provided through data parameter */
|
||||||
int (*fill_stats)(void *data, struct field *, unsigned int *);
|
int (*fill_stats)(struct stats_module *, struct extra_counters *, struct field *, unsigned int *);
|
||||||
|
|
||||||
struct stat_col *stats; /* statistics provided by the module */
|
struct stat_col *stats; /* statistics provided by the module */
|
||||||
void *counters; /* initial values of allocated counters */
|
void *counters; /* initial values of allocated counters */
|
||||||
|
|
@ -543,12 +534,6 @@ struct stats_module {
|
||||||
char clearable; /* reset on a clear counters */
|
char clearable; /* reset on a clear counters */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct extra_counters {
|
|
||||||
char *data; /* heap containing counters allocated in a linear fashion */
|
|
||||||
size_t size; /* size of allocated data */
|
|
||||||
enum counters_type type; /* type of object containing the counters */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* stats_domain is used in a flag as a 1 byte field */
|
/* stats_domain is used in a flag as a 1 byte field */
|
||||||
enum stats_domain {
|
enum stats_domain {
|
||||||
STATS_DOMAIN_PROXY = 0,
|
STATS_DOMAIN_PROXY = 0,
|
||||||
|
|
@ -593,58 +578,9 @@ struct show_stat_ctx {
|
||||||
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
|
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
|
||||||
int st_code; /* the status code returned by an action */
|
int st_code; /* the status code returned by an action */
|
||||||
struct buffer chunk; /* temporary buffer which holds a single-line output */
|
struct buffer chunk; /* temporary buffer which holds a single-line output */
|
||||||
|
struct watcher px_watch; /* watcher to automatically update obj1 on backend deletion */
|
||||||
struct watcher srv_watch; /* watcher to automatically update obj2 on server deletion */
|
struct watcher srv_watch; /* watcher to automatically update obj2 on server deletion */
|
||||||
enum stat_state state; /* phase of output production */
|
enum stat_state state; /* phase of output production */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern THREAD_LOCAL void *trash_counters;
|
|
||||||
|
|
||||||
#define EXTRA_COUNTERS(name) \
|
|
||||||
struct extra_counters *name
|
|
||||||
|
|
||||||
#define EXTRA_COUNTERS_GET(counters, mod) \
|
|
||||||
(likely(counters) ? \
|
|
||||||
((void *)((counters)->data + (mod)->counters_off[(counters)->type])) : \
|
|
||||||
(trash_counters))
|
|
||||||
|
|
||||||
#define EXTRA_COUNTERS_REGISTER(counters, ctype, alloc_failed_label) \
|
|
||||||
do { \
|
|
||||||
typeof(*counters) _ctr; \
|
|
||||||
_ctr = calloc(1, sizeof(*_ctr)); \
|
|
||||||
if (!_ctr) \
|
|
||||||
goto alloc_failed_label; \
|
|
||||||
_ctr->type = (ctype); \
|
|
||||||
*(counters) = _ctr; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXTRA_COUNTERS_ADD(mod, counters, new_counters, csize) \
|
|
||||||
do { \
|
|
||||||
typeof(counters) _ctr = (counters); \
|
|
||||||
(mod)->counters_off[_ctr->type] = _ctr->size; \
|
|
||||||
_ctr->size += (csize); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXTRA_COUNTERS_ALLOC(counters, alloc_failed_label) \
|
|
||||||
do { \
|
|
||||||
typeof(counters) _ctr = (counters); \
|
|
||||||
_ctr->data = malloc((_ctr)->size); \
|
|
||||||
if (!_ctr->data) \
|
|
||||||
goto alloc_failed_label; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXTRA_COUNTERS_INIT(counters, mod, init_counters, init_counters_size) \
|
|
||||||
do { \
|
|
||||||
typeof(counters) _ctr = (counters); \
|
|
||||||
memcpy(_ctr->data + mod->counters_off[_ctr->type], \
|
|
||||||
(init_counters), (init_counters_size)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXTRA_COUNTERS_FREE(counters) \
|
|
||||||
do { \
|
|
||||||
if (counters) { \
|
|
||||||
free((counters)->data); \
|
|
||||||
free(counters); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif /* _HAPROXY_STATS_T_H */
|
#endif /* _HAPROXY_STATS_T_H */
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#define _HAPROXY_STATS_H
|
#define _HAPROXY_STATS_H
|
||||||
|
|
||||||
#include <haproxy/api.h>
|
#include <haproxy/api.h>
|
||||||
|
#include <haproxy/counters.h>
|
||||||
#include <haproxy/listener-t.h>
|
#include <haproxy/listener-t.h>
|
||||||
#include <haproxy/stats-t.h>
|
#include <haproxy/stats-t.h>
|
||||||
#include <haproxy/tools-t.h>
|
#include <haproxy/tools-t.h>
|
||||||
|
|
@ -167,7 +168,8 @@ static inline enum stats_domain_px_cap stats_px_get_cap(uint32_t domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
int stats_allocate_proxy_counters_internal(struct extra_counters **counters,
|
int stats_allocate_proxy_counters_internal(struct extra_counters **counters,
|
||||||
int type, int px_cap);
|
int type, int px_cap,
|
||||||
|
char **storage, size_t step);
|
||||||
int stats_allocate_proxy_counters(struct proxy *px);
|
int stats_allocate_proxy_counters(struct proxy *px);
|
||||||
|
|
||||||
void stats_register_module(struct stats_module *m);
|
void stats_register_module(struct stats_module *m);
|
||||||
|
|
|
||||||
|
|
@ -349,19 +349,6 @@ struct sedesc {
|
||||||
unsigned long long kop; /* Known outgoing payload length (see above) */
|
unsigned long long kop; /* Known outgoing payload length (see above) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* sc_app_ops describes the application layer's operations and notification
|
|
||||||
* callbacks when I/O activity is reported and to use to perform shutr/shutw.
|
|
||||||
* There are very few combinations in practice (strm/chk <-> none/mux/applet).
|
|
||||||
*/
|
|
||||||
struct sc_app_ops {
|
|
||||||
void (*chk_rcv)(struct stconn *); /* chk_rcv function, may not be null */
|
|
||||||
void (*chk_snd)(struct stconn *); /* chk_snd function, may not be null */
|
|
||||||
void (*abort)(struct stconn *); /* abort function, may not be null */
|
|
||||||
void (*shutdown)(struct stconn *); /* shutdown function, may not be null */
|
|
||||||
int (*wake)(struct stconn *); /* data-layer callback to report activity */
|
|
||||||
char name[8]; /* data layer name, zero-terminated */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This structure describes the elements of a connection relevant to a stream
|
* This structure describes the elements of a connection relevant to a stream
|
||||||
*/
|
*/
|
||||||
|
|
@ -383,7 +370,6 @@ struct stconn {
|
||||||
struct wait_event wait_event; /* We're in a wait list */
|
struct wait_event wait_event; /* We're in a wait list */
|
||||||
struct sedesc *sedesc; /* points to the stream endpoint descriptor */
|
struct sedesc *sedesc; /* points to the stream endpoint descriptor */
|
||||||
enum obj_type *app; /* points to the applicative point (stream or check) */
|
enum obj_type *app; /* points to the applicative point (stream or check) */
|
||||||
const struct sc_app_ops *app_ops; /* general operations used at the app layer */
|
|
||||||
struct sockaddr_storage *src; /* source address (pool), when known, otherwise NULL */
|
struct sockaddr_storage *src; /* source address (pool), when known, otherwise NULL */
|
||||||
struct sockaddr_storage *dst; /* destination address (pool), when known, otherwise NULL */
|
struct sockaddr_storage *dst; /* destination address (pool), when known, otherwise NULL */
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ void sc_destroy(struct stconn *sc);
|
||||||
int sc_reset_endp(struct stconn *sc);
|
int sc_reset_endp(struct stconn *sc);
|
||||||
|
|
||||||
struct appctx *sc_applet_create(struct stconn *sc, struct applet *app);
|
struct appctx *sc_applet_create(struct stconn *sc, struct applet *app);
|
||||||
|
int sc_applet_process(struct stconn *sc);
|
||||||
|
int sc_conn_process(struct stconn *sc);
|
||||||
|
|
||||||
void sc_conn_prepare_endp_upgrade(struct stconn *sc);
|
void sc_conn_prepare_endp_upgrade(struct stconn *sc);
|
||||||
void sc_conn_abort_endp_upgrade(struct stconn *sc);
|
void sc_conn_abort_endp_upgrade(struct stconn *sc);
|
||||||
|
|
@ -349,16 +351,6 @@ static inline struct hstream *sc_hstream(const struct stconn *sc)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the name of the application layer's name for the stconn,
|
|
||||||
* or "NONE" when none is attached.
|
|
||||||
*/
|
|
||||||
static inline const char *sc_get_data_name(const struct stconn *sc)
|
|
||||||
{
|
|
||||||
if (!sc->app_ops)
|
|
||||||
return "NONE";
|
|
||||||
return sc->app_ops->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns non-zero if the stream connector's Rx path is blocked because of
|
/* Returns non-zero if the stream connector's Rx path is blocked because of
|
||||||
* lack of room in the input buffer. This usually happens after applets failed
|
* lack of room in the input buffer. This usually happens after applets failed
|
||||||
* to deliver data into the channel's buffer and reported it via sc_need_room().
|
* to deliver data into the channel's buffer and reported it via sc_need_room().
|
||||||
|
|
@ -460,7 +452,7 @@ static inline size_t se_nego_ff(struct sedesc *se, struct buffer *input, size_t
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mux->nego_fastfwd(se->sc, input, count, flags);
|
ret = CALL_MUX_WITH_RET(mux, nego_fastfwd(se->sc, input, count, flags));
|
||||||
if (se->iobuf.flags & IOBUF_FL_FF_BLOCKED) {
|
if (se->iobuf.flags & IOBUF_FL_FF_BLOCKED) {
|
||||||
sc_ep_report_blocked_send(se->sc, 0);
|
sc_ep_report_blocked_send(se->sc, 0);
|
||||||
|
|
||||||
|
|
@ -493,7 +485,7 @@ static inline size_t se_done_ff(struct sedesc *se)
|
||||||
size_t to_send = se_ff_data(se);
|
size_t to_send = se_ff_data(se);
|
||||||
|
|
||||||
BUG_ON(!mux->done_fastfwd);
|
BUG_ON(!mux->done_fastfwd);
|
||||||
ret = mux->done_fastfwd(se->sc);
|
ret = CALL_MUX_WITH_RET(mux, done_fastfwd(se->sc));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* Something was forwarded, unblock the zero-copy forwarding.
|
/* Something was forwarded, unblock the zero-copy forwarding.
|
||||||
* If all data was sent, report and send activity.
|
* If all data was sent, report and send activity.
|
||||||
|
|
@ -525,7 +517,7 @@ static inline size_t se_done_ff(struct sedesc *se)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
se->sc->bytes_out += ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,7 @@ enum {
|
||||||
STRM_EVT_SHUT_SRV_DOWN = 0x00000004, /* Must be shut because the selected server became available */
|
STRM_EVT_SHUT_SRV_DOWN = 0x00000004, /* Must be shut because the selected server became available */
|
||||||
STRM_EVT_SHUT_SRV_UP = 0x00000008, /* Must be shut because a preferred server became available */
|
STRM_EVT_SHUT_SRV_UP = 0x00000008, /* Must be shut because a preferred server became available */
|
||||||
STRM_EVT_KILLED = 0x00000010, /* Must be shut for external reason */
|
STRM_EVT_KILLED = 0x00000010, /* Must be shut for external reason */
|
||||||
|
STRM_EVT_RES = 0x00000020, /* A requested resource is available (a buffer, a conn_slot...) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This function is used to report flags in debugging tools. Please reflect
|
/* This function is used to report flags in debugging tools. Please reflect
|
||||||
|
|
|
||||||
|
|
@ -412,6 +412,7 @@ static inline void stream_shutdown(struct stream *s, int why)
|
||||||
static inline unsigned int stream_map_task_state(unsigned int state)
|
static inline unsigned int stream_map_task_state(unsigned int state)
|
||||||
{
|
{
|
||||||
return ((state & TASK_WOKEN_TIMER) ? STRM_EVT_TIMER : 0) |
|
return ((state & TASK_WOKEN_TIMER) ? STRM_EVT_TIMER : 0) |
|
||||||
|
((state & TASK_WOKEN_RES) ? STRM_EVT_RES : 0) |
|
||||||
((state & TASK_WOKEN_MSG) ? STRM_EVT_MSG : 0) |
|
((state & TASK_WOKEN_MSG) ? STRM_EVT_MSG : 0) |
|
||||||
((state & TASK_F_UEVT1) ? STRM_EVT_SHUT_SRV_DOWN : 0) |
|
((state & TASK_F_UEVT1) ? STRM_EVT_SHUT_SRV_DOWN : 0) |
|
||||||
((state & TASK_F_UEVT3) ? STRM_EVT_SHUT_SRV_UP : 0) |
|
((state & TASK_F_UEVT3) ? STRM_EVT_SHUT_SRV_UP : 0) |
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,6 @@ struct notification {
|
||||||
* on return.
|
* on return.
|
||||||
*/
|
*/
|
||||||
#define TASK_COMMON \
|
#define TASK_COMMON \
|
||||||
struct { \
|
|
||||||
unsigned int state; /* task state : bitfield of TASK_ */ \
|
unsigned int state; /* task state : bitfield of TASK_ */ \
|
||||||
int tid; /* tid of task/tasklet. <0 = local for tasklet, unbound for task */ \
|
int tid; /* tid of task/tasklet. <0 = local for tasklet, unbound for task */ \
|
||||||
struct task *(*process)(struct task *t, void *ctx, unsigned int state); /* the function which processes the task */ \
|
struct task *(*process)(struct task *t, void *ctx, unsigned int state); /* the function which processes the task */ \
|
||||||
|
|
@ -139,11 +138,14 @@ struct notification {
|
||||||
uint32_t wake_date; /* date of the last task wakeup */ \
|
uint32_t wake_date; /* date of the last task wakeup */ \
|
||||||
unsigned int calls; /* number of times process was called */ \
|
unsigned int calls; /* number of times process was called */ \
|
||||||
TASK_DEBUG_STORAGE; \
|
TASK_DEBUG_STORAGE; \
|
||||||
}
|
short last_run; /* 16-bit now_ms of last run */
|
||||||
|
/* a 16- or 48-bit hole remains here and is used by task */
|
||||||
|
|
||||||
/* The base for all tasks */
|
/* The base for all tasks */
|
||||||
struct task {
|
struct task {
|
||||||
TASK_COMMON; /* must be at the beginning! */
|
TASK_COMMON; /* must be at the beginning! */
|
||||||
|
short nice; /* task prio from -1024 to +1024 */
|
||||||
|
int expire; /* next expiration date for this task, in ticks */
|
||||||
struct eb32_node rq; /* ebtree node used to hold the task in the run queue */
|
struct eb32_node rq; /* ebtree node used to hold the task in the run queue */
|
||||||
/* WARNING: the struct task is often aliased as a struct tasklet when
|
/* WARNING: the struct task is often aliased as a struct tasklet when
|
||||||
* it is NOT in the run queue. The tasklet has its struct list here
|
* it is NOT in the run queue. The tasklet has its struct list here
|
||||||
|
|
@ -151,14 +153,12 @@ struct task {
|
||||||
* ever reorder these fields without taking this into account!
|
* ever reorder these fields without taking this into account!
|
||||||
*/
|
*/
|
||||||
struct eb32_node wq; /* ebtree node used to hold the task in the wait queue */
|
struct eb32_node wq; /* ebtree node used to hold the task in the wait queue */
|
||||||
int expire; /* next expiration date for this task, in ticks */
|
|
||||||
short nice; /* task prio from -1024 to +1024 */
|
|
||||||
/* 16-bit hole here */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* lightweight tasks, without priority, mainly used for I/Os */
|
/* lightweight tasks, without priority, mainly used for I/Os */
|
||||||
struct tasklet {
|
struct tasklet {
|
||||||
TASK_COMMON; /* must be at the beginning! */
|
TASK_COMMON; /* must be at the beginning! */
|
||||||
|
/* 48-bit hole here */
|
||||||
struct list list;
|
struct list list;
|
||||||
/* WARNING: the struct task is often aliased as a struct tasklet when
|
/* WARNING: the struct task is often aliased as a struct tasklet when
|
||||||
* it is not in the run queue. The task has its struct rq here where
|
* it is not in the run queue. The task has its struct rq here where
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ enum tcpcheck_rule_type {
|
||||||
/* Unused 0x000000A0..0x00000FF0 (reserved for future proto) */
|
/* Unused 0x000000A0..0x00000FF0 (reserved for future proto) */
|
||||||
#define TCPCHK_RULES_TCP_CHK 0x00000FF0
|
#define TCPCHK_RULES_TCP_CHK 0x00000FF0
|
||||||
#define TCPCHK_RULES_PROTO_CHK 0x00000FF0 /* Mask to cover protocol check */
|
#define TCPCHK_RULES_PROTO_CHK 0x00000FF0 /* Mask to cover protocol check */
|
||||||
|
#define TCPCHK_RULES_MAY_USE_SBUF 0x00001000 /* checks may try to use small buffers if possible for the request */
|
||||||
|
|
||||||
struct check;
|
struct check;
|
||||||
struct tcpcheck_connect {
|
struct tcpcheck_connect {
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,7 @@ enum lock_label {
|
||||||
QC_CID_LOCK,
|
QC_CID_LOCK,
|
||||||
CACHE_LOCK,
|
CACHE_LOCK,
|
||||||
GUID_LOCK,
|
GUID_LOCK,
|
||||||
|
PROXIES_DEL_LOCK,
|
||||||
OTHER_LOCK,
|
OTHER_LOCK,
|
||||||
/* WT: make sure never to use these ones outside of development,
|
/* WT: make sure never to use these ones outside of development,
|
||||||
* we need them for lock profiling!
|
* we need them for lock profiling!
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,41 @@ enum {
|
||||||
/* we have 4 buffer-wait queues, in highest to lowest emergency order */
|
/* we have 4 buffer-wait queues, in highest to lowest emergency order */
|
||||||
#define DYNBUF_NBQ 4
|
#define DYNBUF_NBQ 4
|
||||||
|
|
||||||
|
/* execution context, for tracing resource usage or warning origins */
|
||||||
|
enum thread_exec_ctx_type {
|
||||||
|
TH_EX_CTX_NONE = 0, /* context not filled */
|
||||||
|
TH_EX_CTX_OTHER, /* context only known by a generic pointer */
|
||||||
|
TH_EX_CTX_INITCALL, /* the pointer is an initcall providing file:line */
|
||||||
|
TH_EX_CTX_CALLER, /* the pointer is an ha_caller of the caller providing file:line etc */
|
||||||
|
TH_EX_CTX_SMPF, /* directly registered sample fetch function, using .smpf_kwl */
|
||||||
|
TH_EX_CTX_CONV, /* directly registered converter function, using .conv_kwl */
|
||||||
|
TH_EX_CTX_FUNC, /* hopefully recognizable function/callback, using .pointer */
|
||||||
|
TH_EX_CTX_ACTION, /* directly registered action function, using .action_kwl */
|
||||||
|
TH_EX_CTX_FLT, /* filter whose config is in .flt_conf */
|
||||||
|
TH_EX_CTX_MUX, /* mux whose mux_ops is in .mux_ops */
|
||||||
|
TH_EX_CTX_TASK, /* task or tasklet whose function is in .task */
|
||||||
|
TH_EX_CTX_APPLET, /* applet whose applet is in .applet */
|
||||||
|
TH_EX_CTX_CLI_KWL, /* CLI keyword list, using .cli_kwl */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct thread_exec_ctx {
|
||||||
|
enum thread_exec_ctx_type type;
|
||||||
|
/* 32-bit hole here on 64-bit platforms */
|
||||||
|
union {
|
||||||
|
const void *pointer; /* generic pointer (for other) */
|
||||||
|
const struct initcall *initcall; /* used with TH_EX_CTX_INITCALL */
|
||||||
|
const struct ha_caller *ha_caller; /* used with TH_EX_CTX_CALLER */
|
||||||
|
const struct sample_fetch_kw_list *smpf_kwl; /* used with TH_EX_CTX_SMPF */
|
||||||
|
const struct sample_conv_kw_list *conv_kwl; /* used with TH_EX_CTX_CONV */
|
||||||
|
const struct action_kw_list *action_kwl; /* used with TH_EX_CTX_ACTION */
|
||||||
|
const struct flt_conf *flt_conf; /* used with TH_EX_CTX_FLTCONF */
|
||||||
|
const struct mux_ops *mux_ops; /* used with TH_EX_CTX_MUX */
|
||||||
|
const struct task *(*task)(struct task *, void *, unsigned int); /* used with TH_EX_CTX_TASK */
|
||||||
|
const struct applet *applet; /* used with TH_EX_CTX_APPLET */
|
||||||
|
const struct cli_kw_list *cli_kwl; /* used with TH_EX_CTX_CLI_KWL */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/* Thread group information. This defines a base and a count of global thread
|
/* Thread group information. This defines a base and a count of global thread
|
||||||
* IDs which belong to it, and which can be looked up into thread_info/ctx. It
|
* IDs which belong to it, and which can be looked up into thread_info/ctx. It
|
||||||
* is set up during parsing and is stable during operation. Thread groups start
|
* is set up during parsing and is stable during operation. Thread groups start
|
||||||
|
|
@ -172,8 +207,7 @@ struct thread_ctx {
|
||||||
uint64_t curr_mono_time; /* latest system wide monotonic time (leaving poll) */
|
uint64_t curr_mono_time; /* latest system wide monotonic time (leaving poll) */
|
||||||
|
|
||||||
ulong lock_history; /* history of used locks, see thread.h for more details */
|
ulong lock_history; /* history of used locks, see thread.h for more details */
|
||||||
|
struct thread_exec_ctx exec_ctx; /* current execution context when known, or NULL */
|
||||||
/* around 56 unused bytes here */
|
|
||||||
|
|
||||||
// fourth cache line here on 64 bits: accessed mostly using atomic ops
|
// fourth cache line here on 64 bits: accessed mostly using atomic ops
|
||||||
ALWAYS_ALIGN(64);
|
ALWAYS_ALIGN(64);
|
||||||
|
|
@ -199,6 +233,7 @@ struct thread_ctx {
|
||||||
struct buffer *last_dump_buffer; /* Copy of last buffer used for a dump; may be NULL or invalid; for post-mortem only */
|
struct buffer *last_dump_buffer; /* Copy of last buffer used for a dump; may be NULL or invalid; for post-mortem only */
|
||||||
unsigned long long total_streams; /* Total number of streams created on this thread */
|
unsigned long long total_streams; /* Total number of streams created on this thread */
|
||||||
unsigned int stream_cnt; /* Number of streams attached to this thread */
|
unsigned int stream_cnt; /* Number of streams attached to this thread */
|
||||||
|
unsigned int rq_tot_peak; /* total run queue size last call */
|
||||||
|
|
||||||
// around 68 bytes here for shared variables
|
// around 68 bytes here for shared variables
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,4 +117,42 @@ static inline void thread_set_pin_grp1(struct thread_set *ts, ulong mask)
|
||||||
ts->rel[i] = 0;
|
ts->rel[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* switches the current execution context to <ctx> and returns the previous one
|
||||||
|
* so that this may even be used to save and restore. Setting EXEC_CTX_NONE
|
||||||
|
* resets it. It's efficient because it uses a pair of registers on input and
|
||||||
|
* output.
|
||||||
|
*/
|
||||||
|
static inline struct thread_exec_ctx switch_exec_ctx(const struct thread_exec_ctx ctx)
|
||||||
|
{
|
||||||
|
const struct thread_exec_ctx prev = th_ctx->exec_ctx;
|
||||||
|
|
||||||
|
th_ctx->exec_ctx = ctx;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used to reset the execution context */
|
||||||
|
#define EXEC_CTX_NONE ((struct thread_exec_ctx){ .type = 0, .pointer = NULL })
|
||||||
|
|
||||||
|
/* make an execution context from a type and a pointer */
|
||||||
|
#define EXEC_CTX_MAKE(_type, _pointer) ((struct thread_exec_ctx){ .type = (_type), .pointer = (_pointer) })
|
||||||
|
|
||||||
|
/* execute expression <expr> under context <new_ctx> then restore the previous
|
||||||
|
* one, and return the expression's return value.
|
||||||
|
*/
|
||||||
|
#define EXEC_CTX_WITH_RET(new_ctx, expr) ({ \
|
||||||
|
const struct thread_exec_ctx __prev_ctx = switch_exec_ctx(new_ctx); \
|
||||||
|
typeof(expr) __ret = (expr); \
|
||||||
|
switch_exec_ctx(__prev_ctx); \
|
||||||
|
__ret; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* execute expression <expr> under context <new_ctx> then restore the previous
|
||||||
|
* one. This one has no return value.
|
||||||
|
*/
|
||||||
|
#define EXEC_CTX_NO_RET(new_ctx, expr) do { \
|
||||||
|
const struct thread_exec_ctx __prev_ctx = switch_exec_ctx(new_ctx); \
|
||||||
|
do { expr; } while (0); \
|
||||||
|
switch_exec_ctx(__prev_ctx); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif /* _HAPROXY_TINFO_H */
|
#endif /* _HAPROXY_TINFO_H */
|
||||||
|
|
|
||||||
|
|
@ -1147,10 +1147,13 @@ void dump_hex(struct buffer *out, const char *pfx, const void *buf, int len, int
|
||||||
int may_access(const void *ptr);
|
int may_access(const void *ptr);
|
||||||
const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *addr);
|
const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *addr);
|
||||||
const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *addr);
|
const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *addr);
|
||||||
|
void make_tar_header(char *output, const char *pfx, const char *fname, const char *link, size_t size, mode_t mode);
|
||||||
|
int load_file_into_tar(char **storage, size_t *size, const char *pfx, const char *fname, const char *input, const char *link);
|
||||||
const char *get_exec_path(void);
|
const char *get_exec_path(void);
|
||||||
void *get_sym_curr_addr(const char *name);
|
void *get_sym_curr_addr(const char *name);
|
||||||
void *get_sym_next_addr(const char *name);
|
void *get_sym_next_addr(const char *name);
|
||||||
int dump_libs(struct buffer *output, int with_addr);
|
int dump_libs(struct buffer *output, int with_addr);
|
||||||
|
void collect_libs(void);
|
||||||
|
|
||||||
/* Note that this may result in opening libgcc() on first call, so it may need
|
/* Note that this may result in opening libgcc() on first call, so it may need
|
||||||
* to have been called once before chrooting.
|
* to have been called once before chrooting.
|
||||||
|
|
@ -1324,6 +1327,62 @@ static inline uint statistical_prng_range(uint range)
|
||||||
return mul32hi(statistical_prng(), range ? range - 1 : 0);
|
return mul32hi(statistical_prng(), range ? range - 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The functions below are used to hash one or two pointers together and reduce
|
||||||
|
* the result to fit into a given number of bits. The first part is made of a
|
||||||
|
* multiplication (and possibly an addition) by one or two prime numbers giving
|
||||||
|
* a 64-bit number whose center bits are the most distributed, and the second
|
||||||
|
* part will reuse this value and return a mix of the most variable bits that
|
||||||
|
* fits in the requested size. The most convenient approach is to directly
|
||||||
|
* call ptr_hash() / ptr2_hash(), though for some specific use cases where a
|
||||||
|
* second value could be useful, one may prefer to call the lower level
|
||||||
|
* operations instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* reduce a 64-bit pointer hash to <bits> bits */
|
||||||
|
static forceinline uint _ptr_hash_reduce(unsigned long long x, const int bits)
|
||||||
|
{
|
||||||
|
if (!bits)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sizeof(long) == 4)
|
||||||
|
x ^= x >> 32;
|
||||||
|
else
|
||||||
|
x >>= 31 - (bits + 1) / 2;
|
||||||
|
return x & (~0U >> (-bits & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* single-pointer version, low-level, use ptr_hash() instead */
|
||||||
|
static forceinline ullong _ptr_hash(const void *p)
|
||||||
|
{
|
||||||
|
unsigned long long x = (unsigned long)p;
|
||||||
|
|
||||||
|
x *= 0xacd1be85U;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* two-pointer version, low-level, use ptr2_hash() instead */
|
||||||
|
static forceinline ullong _ptr2_hash(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
unsigned long long x = (unsigned long)p1;
|
||||||
|
unsigned long long y = (unsigned long)p2;
|
||||||
|
|
||||||
|
x *= 0xacd1be85U;
|
||||||
|
y *= 0x9d28e4e9U;
|
||||||
|
return x ^ y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* two-pointer plus arg version, low-level, use ptr2_hash_arg() instead */
|
||||||
|
static forceinline ullong _ptr2_hash_arg(const void *p1, const void *p2, ulong arg)
|
||||||
|
{
|
||||||
|
unsigned long long x = (unsigned long)p1;
|
||||||
|
unsigned long long y = (unsigned long)p2;
|
||||||
|
|
||||||
|
x *= 0xacd1be85U;
|
||||||
|
x += arg;
|
||||||
|
y *= 0x9d28e4e9U;
|
||||||
|
return x ^ y;
|
||||||
|
}
|
||||||
|
|
||||||
/* returns a hash on <bits> bits of pointer <p> that is suitable for being used
|
/* returns a hash on <bits> bits of pointer <p> that is suitable for being used
|
||||||
* to compute statistic buckets, in that it's fast and reasonably distributed
|
* to compute statistic buckets, in that it's fast and reasonably distributed
|
||||||
* thanks to mixing the bits via a multiplication by a prime number and using
|
* thanks to mixing the bits via a multiplication by a prime number and using
|
||||||
|
|
@ -1337,17 +1396,7 @@ static inline uint statistical_prng_range(uint range)
|
||||||
*/
|
*/
|
||||||
static forceinline uint ptr_hash(const void *p, const int bits)
|
static forceinline uint ptr_hash(const void *p, const int bits)
|
||||||
{
|
{
|
||||||
unsigned long long x = (unsigned long)p;
|
return _ptr_hash_reduce(_ptr_hash(p), bits);
|
||||||
|
|
||||||
if (!bits)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
x *= 0xacd1be85U;
|
|
||||||
if (sizeof(long) == 4)
|
|
||||||
x ^= x >> 32;
|
|
||||||
else
|
|
||||||
x >>= 31 - (bits + 1) / 2;
|
|
||||||
return x & (~0U >> (-bits & 31));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same as above but works on two pointers. It will return the same values
|
/* Same as above but works on two pointers. It will return the same values
|
||||||
|
|
@ -1355,20 +1404,15 @@ static forceinline uint ptr_hash(const void *p, const int bits)
|
||||||
*/
|
*/
|
||||||
static forceinline uint ptr2_hash(const void *p1, const void *p2, const int bits)
|
static forceinline uint ptr2_hash(const void *p1, const void *p2, const int bits)
|
||||||
{
|
{
|
||||||
unsigned long long x = (unsigned long)p1;
|
return _ptr_hash_reduce(_ptr2_hash(p1, p2), bits);
|
||||||
unsigned long long y = (unsigned long)p2;
|
}
|
||||||
|
|
||||||
if (!bits)
|
/* Same as above but works on two pointers and a long argument. It will return
|
||||||
return 0;
|
* the same values if the second pointer is NULL.
|
||||||
|
*/
|
||||||
x *= 0xacd1be85U;
|
static forceinline uint ptr2_hash_arg(const void *p1, const void *p2, ulong arg, const int bits)
|
||||||
y *= 0x9d28e4e9U;
|
{
|
||||||
x ^= y;
|
return _ptr_hash_reduce(_ptr2_hash_arg(p1, p2, arg), bits);
|
||||||
if (sizeof(long) == 4)
|
|
||||||
x ^= x >> 32;
|
|
||||||
else
|
|
||||||
x >>= 33 - bits / 2;
|
|
||||||
return x & (~0U >> (-bits & 31));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1499,4 +1543,6 @@ void ha_freearray(char ***array);
|
||||||
|
|
||||||
void ha_memset_s(void *s, int c, size_t n);
|
void ha_memset_s(void *s, int c, size_t n);
|
||||||
|
|
||||||
|
void chunk_append_thread_ctx(struct buffer *output, const struct thread_exec_ctx *ctx, const char *pfx, const char *sfx);
|
||||||
|
|
||||||
#endif /* _HAPROXY_TOOLS_H */
|
#endif /* _HAPROXY_TOOLS_H */
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ struct trace_source {
|
||||||
const void *lockon_ptr; // what to lockon when lockon is set
|
const void *lockon_ptr; // what to lockon when lockon is set
|
||||||
const struct trace_source *follow; // other trace source's tracker to follow
|
const struct trace_source *follow; // other trace source's tracker to follow
|
||||||
int cmdline; // true if source was activated via -dt command line args
|
int cmdline; // true if source was activated via -dt command line args
|
||||||
};
|
} THREAD_ALIGNED();
|
||||||
|
|
||||||
#endif /* _HAPROXY_TRACE_T_H */
|
#endif /* _HAPROXY_TRACE_T_H */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,8 @@ void trace_no_cb(enum trace_level level, uint64_t mask, const struct trace_sourc
|
||||||
|
|
||||||
void trace_register_source(struct trace_source *source);
|
void trace_register_source(struct trace_source *source);
|
||||||
|
|
||||||
int trace_parse_cmd(const char *arg_src, char **errmsg);
|
int trace_add_cmd(const char *arg_src, char **errmsg);
|
||||||
|
void trace_parse_cmds(void);
|
||||||
|
|
||||||
/* return a single char to describe a trace state */
|
/* return a single char to describe a trace state */
|
||||||
static inline char trace_state_char(enum trace_state st)
|
static inline char trace_state_char(enum trace_state st)
|
||||||
|
|
|
||||||
13
reg-tests/jwt/ec_decrypt.crt
Normal file
13
reg-tests/jwt/ec_decrypt.crt
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICBTCCAaugAwIBAgIUN+Ne3W00v5RwrlIBqhub+WHgq3kwCgYIKoZIzj0EAwIw
|
||||||
|
VzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
|
||||||
|
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHZm9vLmJhcjAgFw0yNjAy
|
||||||
|
MjYxMDM5MjhaGA8yMDUzMDcxNDEwMzkyOFowVzELMAkGA1UEBhMCQVUxEzARBgNV
|
||||||
|
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
|
||||||
|
ZDEQMA4GA1UEAwwHZm9vLmJhcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGwE
|
||||||
|
ope2KbYUXi5bSLGiQmkaxO17SwkVbTqRrXTztIx99xj9qfSrVKFqN3lnaNDXAclG
|
||||||
|
GnfmU/j7xsEocZdYmPujUzBRMB0GA1UdDgQWBBQZSL9UUhRofXo5X9BoS0XBug4i
|
||||||
|
DzAfBgNVHSMEGDAWgBQZSL9UUhRofXo5X9BoS0XBug4iDzAPBgNVHRMBAf8EBTAD
|
||||||
|
AQH/MAoGCCqGSM49BAMCA0gAMEUCIQDFDrvj5p9R7wmMRoJGUuEJu7I2xYtXDcOP
|
||||||
|
lLE0quJtvwIgWW7vuM3B+ruCslhIrMMqD+DYeguxAxi+aHRVMnBig/c=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
5
reg-tests/jwt/ec_decrypt.key
Normal file
5
reg-tests/jwt/ec_decrypt.key
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6qbbYYII1zqqmlDH
|
||||||
|
hTwJt+JYBe+ELI02yAecAx+nD4yhRANCAARsBKKXtim2FF4uW0ixokJpGsTte0sJ
|
||||||
|
FW06ka1087SMffcY/an0q1Shajd5Z2jQ1wHJRhp35lP4+8bBKHGXWJj7
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -16,7 +16,7 @@ feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
|
||||||
feature cmd "command -v socat"
|
feature cmd "command -v socat"
|
||||||
feature ignore_unknown_macro
|
feature ignore_unknown_macro
|
||||||
|
|
||||||
server s1 -repeat 27 {
|
server s1 -repeat 40 {
|
||||||
rxreq
|
rxreq
|
||||||
txresp
|
txresp
|
||||||
} -start
|
} -start
|
||||||
|
|
@ -542,3 +542,44 @@ client c27 -connect ${h1_mainfe_sock} {
|
||||||
expect resp.http.x-jwt-verify-RS256-var2 == "1"
|
expect resp.http.x-jwt-verify-RS256-var2 == "1"
|
||||||
|
|
||||||
} -run
|
} -run
|
||||||
|
|
||||||
|
client c28 -connect ${h1_mainfe_sock} {
|
||||||
|
# Token content : {"alg":"none"}
|
||||||
|
# {"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}
|
||||||
|
txreq -url "/none" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 200
|
||||||
|
expect resp.http.x-jwt-alg == "none"
|
||||||
|
expect resp.http.x-jwt-verify == "1"
|
||||||
|
} -run
|
||||||
|
|
||||||
|
client c29 -connect ${h1_mainfe_sock} {
|
||||||
|
# Invalid Token : too many subparts
|
||||||
|
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.aa.aa.aa"
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 200
|
||||||
|
expect resp.http.x-jwt-alg == "none"
|
||||||
|
expect resp.http.x-jwt-verify == "-3"
|
||||||
|
|
||||||
|
# Invalid Token : too many subparts
|
||||||
|
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.aa.aa."
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 200
|
||||||
|
expect resp.http.x-jwt-alg == "none"
|
||||||
|
expect resp.http.x-jwt-verify == "-3"
|
||||||
|
|
||||||
|
# Invalid Token : too few subparts
|
||||||
|
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.aa"
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 200
|
||||||
|
expect resp.http.x-jwt-alg == "none"
|
||||||
|
expect resp.http.x-jwt-verify == "-3"
|
||||||
|
|
||||||
|
# Invalid Token : no signature but alg different than "none"
|
||||||
|
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."
|
||||||
|
rxresp
|
||||||
|
expect resp.status == 200
|
||||||
|
expect resp.http.x-jwt-alg == "RS256"
|
||||||
|
expect resp.http.x-jwt-verify == "-3"
|
||||||
|
} -run
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.4-dev2)'"
|
||||||
feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && openssl_version_atleast(1.1.1)'"
|
feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && openssl_version_atleast(1.1.1)'"
|
||||||
feature ignore_unknown_macro
|
feature ignore_unknown_macro
|
||||||
|
|
||||||
server s1 -repeat 20 {
|
server s1 -repeat 30 {
|
||||||
rxreq
|
rxreq
|
||||||
txresp
|
txresp
|
||||||
} -start
|
} -start
|
||||||
|
|
@ -53,6 +53,10 @@ haproxy h1 -conf {
|
||||||
# { "kty": "RSA", "e": "AQAB", "n": "wsqJbopx18NQFYLYOq4ZeMSE89yGiEankUpf25yV8QqroKUGrASj_OeqTWUjwPGKTN1vGFFuHYxiJeAUQH2qQPmg9Oqk6-ATBEKn9COKYniQ5459UxCwmZA2RL6ufhrNyq0JF3GfXkjLDBfhU9zJJEOhknsA0L_c-X4AI3d_NbFdMqxNe1V_UWAlLcbKdwO6iC9fAvwUmDQxgy6R0DC1CMouQpenMRcALaSHar1cm4K-syoNobv3HEuqgZ3s6-hOOSqauqAO0GUozPpaIA7OeruyRl5sTWT0r-iz39bchID2bIKtcqLiFcSYPLBcxmsaQCqRlGhmv6stjTCLV1yT9w", "kid": "ff3c5c96-392e-46ef-a839-6ff16027af78", "d": "b9hXfQ8lOtw8mX1dpqPcoElGhbczz_-xq2znCXQpbBPSZBUddZvchRSH5pSSKPEHlgb3CSGIdpLqsBCv0C_XmCM9ViN8uqsYgDO9uCLIDK5plWttbkqA_EufvW03R9UgIKWmOL3W4g4t-C2mBb8aByaGGVNjLnlb6i186uBsPGkvaeLHbQcRQKAvhOUTeNiyiiCbUGJwCm4avMiZrsz1r81Y1Z5izo0ERxdZymxM3FRZ9vjTB-6DtitvTXXnaAm1JTu6TIpj38u2mnNLkGMbflOpgelMNKBZVxSmfobIbFN8CHVc1UqLK2ElsZ9RCQANgkMHlMkOMj-XT0wHa3VBUQ", "p": "8mgriveKJAp1S7SHqirQAfZafxVuAK_A2QBYPsAUhikfBOvN0HtZjgurPXSJSdgR8KbWV7ZjdJM_eOivIb_XiuAaUdIOXbLRet7t9a_NJtmX9iybhoa9VOJFMBq_rbnbbte2kq0-FnXmv3cukbC2LaEw3aEcDgyURLCgWFqt7M0", "q": "zbbTv5421GowOfKVEuVoA35CEWgl8mdasnEZac2LWxMwKExikKU5LLacLQlcOt7A6n1ZGUC2wyH8mstO5tV34Eug3fnNrbnxFUEE_ZB_njs_rtZnwz57AoUXOXVnd194seIZF9PjdzZcuwXwXbrZ2RSVW8if_ZH5OVYEM1EsA9M", "dp": "1BaIYmIKn1X3InGlcSFcNRtSOnaJdFhRpotCqkRssKUx2qBlxs7ln_5dqLtZkx5VM_UE_GE7yzc6BZOwBxtOftdsr8HVh-14ksSR9rAGEsO2zVBiEuW4qZf_aQM-ScWfU--wcczZ0dT-Ou8P87Bk9K9fjcn0PeaLoz3WTPepzNE", "dq": "kYw2u4_UmWvcXVOeV_VKJ5aQZkJ6_sxTpodRBMPyQmkMHKcW4eKU1mcJju_deqWadw5jGPPpm5yTXm5UkAwfOeookoWpGa7CvVf4kPNI6Aphn3GBjunJHNpPuU6w-wvomGsxd-NqQDGNYKHuFFMcyXO_zWXglQdP_1o1tJ1M-BM", "qi": "j94Ens784M8zsfwWoJhYq9prcSZOGgNbtFWQZO8HP8pcNM9ls7YA4snTtAS_B4peWWFAFZ0LSKPCxAvJnrq69ocmEKEk7ss1Jo062f9pLTQ6cnhMjev3IqLocIFt5Vbsg_PWYpFSR7re6FRbF9EYOM7F2-HRv1idxKCWoyQfBqk" }
|
# { "kty": "RSA", "e": "AQAB", "n": "wsqJbopx18NQFYLYOq4ZeMSE89yGiEankUpf25yV8QqroKUGrASj_OeqTWUjwPGKTN1vGFFuHYxiJeAUQH2qQPmg9Oqk6-ATBEKn9COKYniQ5459UxCwmZA2RL6ufhrNyq0JF3GfXkjLDBfhU9zJJEOhknsA0L_c-X4AI3d_NbFdMqxNe1V_UWAlLcbKdwO6iC9fAvwUmDQxgy6R0DC1CMouQpenMRcALaSHar1cm4K-syoNobv3HEuqgZ3s6-hOOSqauqAO0GUozPpaIA7OeruyRl5sTWT0r-iz39bchID2bIKtcqLiFcSYPLBcxmsaQCqRlGhmv6stjTCLV1yT9w", "kid": "ff3c5c96-392e-46ef-a839-6ff16027af78", "d": "b9hXfQ8lOtw8mX1dpqPcoElGhbczz_-xq2znCXQpbBPSZBUddZvchRSH5pSSKPEHlgb3CSGIdpLqsBCv0C_XmCM9ViN8uqsYgDO9uCLIDK5plWttbkqA_EufvW03R9UgIKWmOL3W4g4t-C2mBb8aByaGGVNjLnlb6i186uBsPGkvaeLHbQcRQKAvhOUTeNiyiiCbUGJwCm4avMiZrsz1r81Y1Z5izo0ERxdZymxM3FRZ9vjTB-6DtitvTXXnaAm1JTu6TIpj38u2mnNLkGMbflOpgelMNKBZVxSmfobIbFN8CHVc1UqLK2ElsZ9RCQANgkMHlMkOMj-XT0wHa3VBUQ", "p": "8mgriveKJAp1S7SHqirQAfZafxVuAK_A2QBYPsAUhikfBOvN0HtZjgurPXSJSdgR8KbWV7ZjdJM_eOivIb_XiuAaUdIOXbLRet7t9a_NJtmX9iybhoa9VOJFMBq_rbnbbte2kq0-FnXmv3cukbC2LaEw3aEcDgyURLCgWFqt7M0", "q": "zbbTv5421GowOfKVEuVoA35CEWgl8mdasnEZac2LWxMwKExikKU5LLacLQlcOt7A6n1ZGUC2wyH8mstO5tV34Eug3fnNrbnxFUEE_ZB_njs_rtZnwz57AoUXOXVnd194seIZF9PjdzZcuwXwXbrZ2RSVW8if_ZH5OVYEM1EsA9M", "dp": "1BaIYmIKn1X3InGlcSFcNRtSOnaJdFhRpotCqkRssKUx2qBlxs7ln_5dqLtZkx5VM_UE_GE7yzc6BZOwBxtOftdsr8HVh-14ksSR9rAGEsO2zVBiEuW4qZf_aQM-ScWfU--wcczZ0dT-Ou8P87Bk9K9fjcn0PeaLoz3WTPepzNE", "dq": "kYw2u4_UmWvcXVOeV_VKJ5aQZkJ6_sxTpodRBMPyQmkMHKcW4eKU1mcJju_deqWadw5jGPPpm5yTXm5UkAwfOeookoWpGa7CvVf4kPNI6Aphn3GBjunJHNpPuU6w-wvomGsxd-NqQDGNYKHuFFMcyXO_zWXglQdP_1o1tJ1M-BM", "qi": "j94Ens784M8zsfwWoJhYq9prcSZOGgNbtFWQZO8HP8pcNM9ls7YA4snTtAS_B4peWWFAFZ0LSKPCxAvJnrq69ocmEKEk7ss1Jo062f9pLTQ6cnhMjev3IqLocIFt5Vbsg_PWYpFSR7re6FRbF9EYOM7F2-HRv1idxKCWoyQfBqk" }
|
||||||
load crt rsa_oeap.pem key rsa_oeap.key jwt on
|
load crt rsa_oeap.pem key rsa_oeap.key jwt on
|
||||||
|
|
||||||
|
# Private key built out of the following JWK:
|
||||||
|
# {"crv":"P-256","d":"6qbbYYII1zqqmlDHhTwJt-JYBe-ELI02yAecAx-nD4w","kty":"EC","x":"bASil7YpthReLltIsaJCaRrE7XtLCRVtOpGtdPO0jH0","y":"9xj9qfSrVKFqN3lnaNDXAclGGnfmU_j7xsEocZdYmPs"}
|
||||||
|
load crt ec_decrypt.crt key ec_decrypt.key jwt on
|
||||||
|
|
||||||
listen main-fe
|
listen main-fe
|
||||||
bind "fd@${mainfe}"
|
bind "fd@${mainfe}"
|
||||||
|
|
||||||
|
|
@ -84,6 +88,11 @@ haproxy h1 -conf {
|
||||||
|
|
||||||
http-request set-var(txn.decrypted) var(txn.jwe),jwt_decrypt_cert(txn.pem)
|
http-request set-var(txn.decrypted) var(txn.jwe),jwt_decrypt_cert(txn.pem)
|
||||||
|
|
||||||
|
.if ssllib_name_startswith(AWS-LC)
|
||||||
|
acl aws_unmanaged var(txn.jwe),jwt_header_query('$.alg') -m end "A128KW" -m end "A192KW"
|
||||||
|
http-request set-var(txn.decrypted) str("AWS-LC UNMANAGED") if aws_unmanaged
|
||||||
|
.endif
|
||||||
|
|
||||||
http-after-response set-header X-Decrypted %[var(txn.decrypted)]
|
http-after-response set-header X-Decrypted %[var(txn.decrypted)]
|
||||||
server s1 ${s1_addr}:${s1_port}
|
server s1 ${s1_addr}:${s1_port}
|
||||||
|
|
||||||
|
|
@ -95,7 +104,7 @@ haproxy h1 -conf {
|
||||||
http-request set-var(txn.decrypted) var(txn.jwe),jwt_decrypt_jwk(txn.jwk)
|
http-request set-var(txn.decrypted) var(txn.jwe),jwt_decrypt_jwk(txn.jwk)
|
||||||
|
|
||||||
.if ssllib_name_startswith(AWS-LC)
|
.if ssllib_name_startswith(AWS-LC)
|
||||||
acl aws_unmanaged var(txn.jwe),jwt_header_query('$.alg') -m str "A128KW"
|
acl aws_unmanaged var(txn.jwe),jwt_header_query('$.alg') -m end "A128KW" -m end "A192KW"
|
||||||
http-request set-var(txn.decrypted) str("AWS-LC UNMANAGED") if aws_unmanaged
|
http-request set-var(txn.decrypted) str("AWS-LC UNMANAGED") if aws_unmanaged
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
|
@ -262,3 +271,53 @@ client c8 -connect ${h1_mainfe_sock} {
|
||||||
expect resp.http.x-decrypted == ""
|
expect resp.http.x-decrypted == ""
|
||||||
} -run
|
} -run
|
||||||
|
|
||||||
|
|
||||||
|
# ECDH-ES
|
||||||
|
client c9 -connect ${h1_mainfe_sock} {
|
||||||
|
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiAiRUNESC1FUyIsICJlbmMiOiAiQTI1NkdDTSIsICJlcGsiOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJZVUg1VlJweURCb3FiUjVCUWlSMGV4anJ0bDdLb24yeTZkejFnM3NuNzZJIiwgInkiOiAiZld2RHFHb3pYNjJnMnRTS19oSkctWkVKNkFCcFhYTS1Tc1hPeE5KUXFtUSJ9fQ..0tN70AQ3P_4uEV4t.zkv7KfnUlDTKjJ82zKCMK_z7OEFk_euXGuJemShf8mnOeEUE4UN8wS5cRJzMQWxcY9d3dIvUCYx0HhzeoXnKqnkEU6be659IVtKpqtceLYKcIkpjj0XiaEalVqIKKXTU2NG2ldNsYwnEDN_XxMnIUPFOy3yJqpOfjf8v98ABYuTWfJVwk3tK9vYCj-ScCf2NK7cEIti_09VCsxMg7z0kvco5UaTXvDjEbPhj_EVfHoPlmDE6EuaO5OX5t3reOoJ1vsM2PEpADiYfmvSZxeWAmmtAH7cvrRIUCcy4Q5pNczh1Pmt0y-uJKtme16YWq8PxVtnb7lY9HDTuPeaMVqvMV6PlQ9vnfsirjpz72qx3ArAeXkIGJsPOGKfgCoW6sAWHQxCzvq8ek7zOaqTAo169PSdtxfBL4MJWxoLg38pODy4cjEGR71YYirthejEMgRs7G1A8ksxgs2bkYGInunUD_iAWkQzxYZhFlLRntWP1ikOKmx9gbqR6K9UiqCK1UG4NXF3o4OV34m-jw-cXMDF2JkekVK2-rhxTbXmqP-VhDrkQ2ANdk7fTW9elFYNisVzE1QjdClMKGhO1fdKiSJ9xSPo3W6pMuquYYN-XT1fLiu3GDtO4ELZWVdwmiucsxv9H2jzPwbhvbvlXwXsmyCBtvumcEUbiYCOIYvlddhTGjZHplvDU73O5SkxUYJTYh7H0DcSiZ-6tcWdRCs605xVZMJ_X91_gZ1tb2_df73lYT_tVo39kw78m3GVFBeK2Zy4JeLheo0fHE7n8lg13uwG77SHwrWSV61KKWhBPZR0bWGi8YvVHnqX0GWklIjpqjbIjYAk4baFv4MO4OvEkPxnGm64NNZWrGEA0U8eEHCgjF1ZagQFNb674Crgd-tRA0QPEAOc9NsnlK1Q-47KIgqNbwoc3VpbpHNLVJT4aKWV5q187YNxarbpeDqguh75M9AgbpT5bSDFhjF83f1kiEDgLdNTkAd-CPAzgtzaEAfxD1K4ViZZZ2DqXgw0PFTFZAWrWqv8Ydi61r5MJ.Srleju8Bifrc_6bqFPUF_w" \
|
||||||
|
-hdr "X-JWK: {\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"DxaAKzwruXJh4IkdieycIJER6w8M1TYMCV3qOa-l9CM\",\"y\":\"_kRI1aD7-PMFwhUpXmcRzw6hALF_xdKwADuKOM-xsak\",\"d\":\"SOu5eRc40yn5yVrg069VjWNH4wsoErN8_AxmH4cI88s\"}"
|
||||||
|
rxresp
|
||||||
|
expect resp.http.x-decrypted == "Sed ut perspiciatis unde omnis iste natus error sit voluptatem doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. porro quisquam est, qui dolorem ipsum quia dolor sit amet, adipisci velit, sed quia non numquam eius modi tempora incidunt ut dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in voluptate velit esse quam nihil molestiae consequatur, vel illum qui eum fugiat quo voluptas nulla pariatur?"
|
||||||
|
|
||||||
|
|
||||||
|
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImVwayI6eyJjcnYiOiJQLTUyMSIsImt0eSI6IkVDIiwieCI6IkFYelVIT0hFdXU1RzlxSHBQOGdXelBub3FQNUpSVmNrYWZGb1VxV0FUQVd6b3FUN0tmX3V5WW5HSElaNkVXdUx0U0NrUnREUHE4WDJlcV9lSDc0QVRQZGwiLCJ5IjoiQVRxelFNWV9PUE9lWUZYNlpGN0l4ZkgwQ2x6RlRjZjVhaE1UTERmMHJYRkczNmdHN1lDMjR1Q2hrR2ZoZHlBT1RRY09kN1ZyQlM4clNZeC03R0hLbzNWNSJ9fQ..kTaw9v3MWCN78jq5OXTWZA.w4o_19dlHEFEhQ0GXI08x-vJnImL_mtZ_oHXTCvfCj_aCEDL4UuiaAU7-yvtM60G3HjNO6TTvmCdvHOTz6Ynrg.H-EbBpTyi5YXNT5DHSFiNBeBcdjmClR_LDARvak4qng" \
|
||||||
|
-hdr "X-JWK: {\"alg\":\"ECDH-ES\",\"crv\":\"P-521\",\"d\":\"AVBp1yn67_t0C8WfJnrhZsgy4TDkA9XktZnwAHcCTUMWTBCURXOjCNCIaCyE65xzIQbZUc9rO-B93XKFO81u8myd\",\"key_ops\":[\"wrapKey\",\"unwrapKey\"],\"kty\":\"EC\",\"x\":\"AByuEl5P9ledNRyj4EjTtQwDcsIYpbNzUqjri5o8GPGLzeTWUzjDBVt1ZyxKfK8VMVQbj8sIrBHncYUqM1Re3pSA\",\"y\":\"AW171IiyQSWx95A9uT1m76XPcAss3jeE7lHgw8mU7yIxSi_SItDYFixJ5Xtf2Vu2BLlmpR0on6VV1UUNIyPk6qwb\"}"
|
||||||
|
rxresp
|
||||||
|
expect resp.http.x-decrypted == "Random test message for ECDH-ES encrypted tokens"
|
||||||
|
|
||||||
|
txreq -url "/pem" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6InhEcUZveF9oR3Q5VjZWSWZjRUpaU1VVTm1uT0V5Qk1BYzZybHlOV09lcjgiLCJ5IjoiUVZmdkstcVJ0V0J1Uk9XVzRnMmlVampqMFN3U1BzYjB6ZE10R0c2czBFUSJ9fQ..0ykoqdP2WMKra2VugMQMzg.dyCI6QGNIf-x4n0DIaXgVnGtoSCOD3sOX7I01djrFdNRRSmPnITcQiJn1lw1LbiZyqZxOLf_mJHw7BRrcgPxBG6gsP3oFBnLeXllcD6kuLtllVofaPDEKdr66W9dp6Cr.002j4NUlGTYz8d_0mTM38A" \
|
||||||
|
-hdr "X-PEM: ${testdir}/ec_decrypt.crt"
|
||||||
|
rxresp
|
||||||
|
expect resp.http.x-decrypted == "Random test message for ECDH-ES encrypted token (with some extra padding for good measure)"
|
||||||
|
|
||||||
|
} -run
|
||||||
|
|
||||||
|
# ECDH-ES+A___KW
|
||||||
|
client c10 -connect ${h1_mainfe_sock} {
|
||||||
|
|
||||||
|
# ECDH-ES+A128KW
|
||||||
|
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiJtc2poQktWNW5oNnBjdjhoRnR0UDlFVXRzaURzWG83T3RCekVZYkVJM1EwIiwieSI6IloxQ3FPQlEya1RNR1lENWdMUWJCaHB0MzRKRkR3dW5TX2ZzSmhsMlc1OWcifX0.5l7YaATvAWFJnWK_HsBPmawJ0RMqrkiwyZ9xAuiYCFSiqWWSr8D82A.0sa1s5V2RcDf0FW6hA1lig.z2DVLxtHeY1fPp6dJHiHEuHLVIQHQ10GfYXeFxwNE7JGyto-D3K1elHQn0Yq4Pitaheja21gnXkJajXhOA0rwQ.YmpToFWmj8XQrXMeXTa9eQ" \
|
||||||
|
-hdr "X-JWK: {\"crv\":\"P-256\",\"d\":\"6qbbYYII1zqqmlDHhTwJt-JYBe-ELI02yAecAx-nD4w\",\"kty\":\"EC\",\"x\":\"bASil7YpthReLltIsaJCaRrE7XtLCRVtOpGtdPO0jH0\",\"y\":\"9xj9qfSrVKFqN3lnaNDXAclGGnfmU_j7xsEocZdYmPs\"}"
|
||||||
|
rxresp
|
||||||
|
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES encrypted tokens|AWS-LC UNMANAGED)"
|
||||||
|
|
||||||
|
txreq -url "/pem" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiJKeUJzcDZtZjVCMWROYUk0ZGppX2pnMm9NdFRRQUd4akxTekdGbGJ0dXZZIiwieSI6IlFfZnlBUmZiMGpjWXFtSTZUNEdXTXA1U2dGYXZiQ3lGUGF3OHhab1BIYzAifX0.JKrKKRF9QdxUyv0KX-MV11eHpP2Vz8Amdh8j3ipd_QP57jkN-OWRCQ.CjpnSVRVV51C10cUwCTaXA.bliaBk7mGYIOGdvgiMg481iC8GiOarRrjIkUgEBuqiSJENmOi90IXgnoVp4qQdi70bJVBNuCYP7Q9sLzZc4X2g.C_TCuAfAH5020v-NdR91BA" \
|
||||||
|
-hdr "X-PEM: ${testdir}/ec_decrypt.crt"
|
||||||
|
rxresp
|
||||||
|
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES\\+A128KW encrypted token|AWS-LC UNMANAGED)"
|
||||||
|
|
||||||
|
|
||||||
|
# ECDH-ES+A192KW
|
||||||
|
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsiY3J2IjoiUC0zODQiLCJrdHkiOiJFQyIsIngiOiJDcTd3Y0MzUm92VFRZSTMzLU9DcXBocjFlN1NzeEZWY0dOQXhEOEpWZHBRQmROaGg3Z2dLNTJKVkJ1RF9uZXVHIiwieSI6IjlaLU1MV09TQ3VZd0JZVTEtcTd2YUREWUZ1WFhqc1EwSmxpWllLVmdOU0dqVHVLY3VXQnJHemV2RzZEeGgyRHQifX0.75lt6Ixq6UhlN8uiaEphy8SiqEVsuD4Rc3QbFcmP7MJUTyt15LcZ3y-M7TJeNBh3Ajy_6K2WooU.cO9tUaQ2eVo0tIuOqb5_Bw.HQ6DqnLhW2Ad0c78WFGgwCStefYdL37xmh2Fa2mCsVNW5q0K3-xeDHYuIP9Q5xBYEY70U6wV5a0iVN87ii_iMA.feLteQh1ickYVJ2ZZ2whoVzNGRHgUpjp" \
|
||||||
|
-hdr "X-JWK: {\"alg\":\"ECDH-ES+A192KW\",\"crv\":\"P-384\",\"d\":\"pj6xIezfwtUakkkLtbRQ9FmN6uN1YJ-TSBkWn4awuDfWiHgqpQHA7_L95Hjks1cK\",\"key_ops\":[\"wrapKey\",\"unwrapKey\"],\"kty\":\"EC\",\"x\":\"JO3ojbUYOzoSb-7lAy-c7VhDIjhEtg4zrPn_NJKuGhat-cuI1c4LvOj3n8p3j4bn\",\"y\":\"CA3i4pN7t6liWxQXyxdDp9t79B8uWuubGADJuGn_2_yl6pufhnQ30OBA590fOtEm\"}"
|
||||||
|
rxresp
|
||||||
|
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES\\+A192KW encrypted tokens|AWS-LC UNMANAGED)"
|
||||||
|
|
||||||
|
|
||||||
|
# ECDH-ES+A256KW
|
||||||
|
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsiY3J2IjoiUC01MjEiLCJrdHkiOiJFQyIsIngiOiJBTFZuZXN6Tl93WVJSWVYtblp3dy1sSkVDTXB2eE1iSENXX3BjY3EyWlF2eFdsNzVKdm5TM3lKbjgzcTE1MlpnWU4zTTB4SUhzQmw1empWZS02OGR4TThwIiwieSI6IkFUX2pGel94RGt0VFY4WWYzZlo1MnRvbE5QWkwwNXlwa0dVTThPWFRNZTBaaVNfYnIzaS0xNHFlWG1OcjA3TFFjNUZMX1VTQkE5WmlyWGRaZkVLUnFqNmEifX0.MqGFvMzpIlwQHeXgPucBkXmS2BaXr2ByUugzD31XrPtxwlWw96vOmfcjSHvda2FGJ1u6InaMMVZMMp75P6AF0kvk8vuM7QF2.kHYblcqwHgXv0xRQrLHwoA.gwFUyTx3RRHWvmqyUL5N6W8HcwbNc1hPTImQPoCNPv6rkhzV1obikVj7sNuTh3Po0nBu2QCKrt-GjJTlD4Q5kw.Q_YZWSkVVxv1rcpySgENN3ZPp-chIYoCGC070kkqiXc" \
|
||||||
|
-hdr "X-JWK: {\"alg\":\"ECDH-ES+A256KW\",\"crv\":\"P-521\",\"d\":\"AGGLpIzSL1jE34wGa-owWCVt2rgk8j3jqh33QQFKwYCJ9abp3vROyQ-dNv6j6PjrnF1EFyY9dDzChNpWmzoOZAp3\",\"key_ops\":[\"wrapKey\",\"unwrapKey\"],\"kty\":\"EC\",\"x\":\"AD0EIUE6Bt_TDcyOPM6VchRocp7AFSeVd6XkVALWf8AFebeMgKIvJsCsGeRdPTO3vWWrR5AOvvpiBfurb9M9Tus-\",\"y\":\"AOeI5d0iF463g3DolhmVFn6MWk764ONuXRexLApjN-Q6_RkcnCieRSZzqqSPMYuEn-N3i4aYfiEPZV0jk8oZKQMQ\"}"
|
||||||
|
rxresp
|
||||||
|
expect resp.http.x-decrypted == "Random test message for ECDH-ES+A256KW encrypted tokens"
|
||||||
|
|
||||||
|
} -run
|
||||||
|
|
|
||||||
88
reg-tests/proxy/cli_del_backend.vtc
Normal file
88
reg-tests/proxy/cli_del_backend.vtc
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
varnishtest "Delete backend via cli"
|
||||||
|
|
||||||
|
feature ignore_unknown_macro
|
||||||
|
|
||||||
|
haproxy h1 -conf {
|
||||||
|
global
|
||||||
|
.if feature(THREAD)
|
||||||
|
thread-groups 1
|
||||||
|
.endif
|
||||||
|
|
||||||
|
defaults
|
||||||
|
mode http
|
||||||
|
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
|
||||||
|
frontend fe
|
||||||
|
bind "fd@${feS}"
|
||||||
|
use_backend be_ref
|
||||||
|
|
||||||
|
listen li
|
||||||
|
bind "fd@${feli}"
|
||||||
|
|
||||||
|
backend be_ref
|
||||||
|
|
||||||
|
backend be
|
||||||
|
server s1 ${s1_addr}:${s1_port} disabled
|
||||||
|
|
||||||
|
# Defaults with tcp-check rules in it
|
||||||
|
# Currently this is the only case of runtime ref on an unnamed default
|
||||||
|
defaults
|
||||||
|
mode http
|
||||||
|
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
option httpchk GET / HTTP/1.1
|
||||||
|
|
||||||
|
backend be_unnamed_def_ref
|
||||||
|
backend be_unnamed_def_ref2
|
||||||
|
} -start
|
||||||
|
|
||||||
|
haproxy h1 -cli {
|
||||||
|
send "experimental-mode on; del backend other"
|
||||||
|
expect ~ "No such backend."
|
||||||
|
|
||||||
|
send "experimental-mode on; del backend li"
|
||||||
|
expect ~ "Cannot delete a listen section."
|
||||||
|
|
||||||
|
send "experimental-mode on; del backend be_ref"
|
||||||
|
expect ~ "This proxy cannot be removed at runtime due to other configuration elements pointing to it."
|
||||||
|
|
||||||
|
send "show stat be 2 -1"
|
||||||
|
expect ~ "be,BACKEND,"
|
||||||
|
|
||||||
|
send "experimental-mode on; del backend be"
|
||||||
|
expect ~ "Backend must be unpublished prior to its deletion."
|
||||||
|
|
||||||
|
send "unpublish backend be;"
|
||||||
|
expect ~ ".*"
|
||||||
|
send "experimental-mode on; del backend be"
|
||||||
|
expect ~ "Only a backend without server can be deleted."
|
||||||
|
|
||||||
|
send "del server be/s1"
|
||||||
|
expect ~ ".*"
|
||||||
|
send "experimental-mode on; del backend be"
|
||||||
|
expect ~ "Backend deleted."
|
||||||
|
|
||||||
|
send "show stat be 2 -1"
|
||||||
|
expect !~ "be,BACKEND,"
|
||||||
|
}
|
||||||
|
|
||||||
|
haproxy h1 -cli {
|
||||||
|
send "show stat be_unnamed_def_ref 2 -1"
|
||||||
|
expect ~ "be_unnamed_def_ref,BACKEND,"
|
||||||
|
|
||||||
|
send "unpublish backend be_unnamed_def_ref;"
|
||||||
|
expect ~ ".*"
|
||||||
|
send "experimental-mode on; del backend be_unnamed_def_ref"
|
||||||
|
expect ~ "Backend deleted."
|
||||||
|
|
||||||
|
send "show stat be_unnamed_def_ref 2 -1"
|
||||||
|
expect !~ "be_unnamed_def_ref,BACKEND,"
|
||||||
|
|
||||||
|
send "unpublish backend be_unnamed_def_ref2;"
|
||||||
|
expect ~ ".*"
|
||||||
|
send "experimental-mode on; del backend be_unnamed_def_ref2"
|
||||||
|
expect ~ "Backend deleted."
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
# show-backports -q -m -r hapee-r2 hapee-r1
|
# show-backports -q -m -r hapee-r2 hapee-r1
|
||||||
|
|
||||||
|
|
||||||
USAGE="Usage: ${0##*/} [-q] [-H] [-m] [-u] [-r reference] [-l logexpr] [-s subject] [-b base] {branch|range} [...] [-- file*]"
|
USAGE="Usage: ${0##*/} [-q] [-H] [-m] [-u] [-L] [-r reference] [-l logexpr] [-s subject] [-b base] {branch|range} [...] [-- file*]"
|
||||||
BASES=( )
|
BASES=( )
|
||||||
BRANCHES=( )
|
BRANCHES=( )
|
||||||
REF=
|
REF=
|
||||||
|
|
@ -39,6 +39,7 @@ SUBJECT=
|
||||||
MISSING=
|
MISSING=
|
||||||
UPSTREAM=
|
UPSTREAM=
|
||||||
BODYHASH=
|
BODYHASH=
|
||||||
|
SINCELAST=
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
[ "$#" -eq 0 ] || echo "$*" >&2
|
[ "$#" -eq 0 ] || echo "$*" >&2
|
||||||
|
|
@ -70,7 +71,7 @@ dump_commit_matrix() {
|
||||||
count=0
|
count=0
|
||||||
# now look up commits
|
# now look up commits
|
||||||
while read ref subject; do
|
while read ref subject; do
|
||||||
if [ -n "$MISSING" -a "${subject:0:9}" = "[RELEASE]" ]; then
|
if [ -n "$MISSING" -o -n "$SINCELAST" ] && [ "${subject:0:9}" = "[RELEASE]" ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -153,6 +154,7 @@ while [ -n "$1" -a -z "${1##-*}" ]; do
|
||||||
-m) MISSING=1 ; shift ;;
|
-m) MISSING=1 ; shift ;;
|
||||||
-u) UPSTREAM=1 ; shift ;;
|
-u) UPSTREAM=1 ; shift ;;
|
||||||
-H) BODYHASH=1 ; shift ;;
|
-H) BODYHASH=1 ; shift ;;
|
||||||
|
-L) SINCELAST=1 ; shift ;;
|
||||||
-h|--help) quit "$USAGE" ;;
|
-h|--help) quit "$USAGE" ;;
|
||||||
*) die "$USAGE" ;;
|
*) die "$USAGE" ;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -255,7 +257,7 @@ if [ -z "$BASE" -a -n "$MISSING" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$BASE" ]; then
|
if [ -z "$BASE" ]; then
|
||||||
err "Warning! No base specified, looking for common ancestor."
|
[ "$QUIET" != "" ] || err "Warning! No base specified, looking for common ancestor."
|
||||||
BASE=$(git merge-base --all "$REF" "${BRANCHES[@]}")
|
BASE=$(git merge-base --all "$REF" "${BRANCHES[@]}")
|
||||||
if [ -z "$BASE" ]; then
|
if [ -z "$BASE" ]; then
|
||||||
die "Couldn't find a common ancestor between these branches"
|
die "Couldn't find a common ancestor between these branches"
|
||||||
|
|
@ -297,9 +299,23 @@ dump_commit_matrix | column -t | \
|
||||||
(
|
(
|
||||||
left_commits=( )
|
left_commits=( )
|
||||||
right_commits=( )
|
right_commits=( )
|
||||||
|
since_last=( )
|
||||||
|
last_bkp=$BASE
|
||||||
while read line; do
|
while read line; do
|
||||||
# append the subject at the end of the line
|
# append the subject at the end of the line
|
||||||
set -- $line
|
set -- $line
|
||||||
|
if [ -n "$SINCELAST" ]; then
|
||||||
|
if [ "${line::1}" = ":" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$2" != "-" ]; then
|
||||||
|
last_bkp="$1"
|
||||||
|
since_last=( )
|
||||||
|
else
|
||||||
|
since_last[${#since_last[@]}]="$1"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
echo -n "$line "
|
echo -n "$line "
|
||||||
if [ "${line::1}" = ":" ]; then
|
if [ "${line::1}" = ":" ]; then
|
||||||
echo "---- Subject ----"
|
echo "---- Subject ----"
|
||||||
|
|
@ -315,7 +331,14 @@ dump_commit_matrix | column -t | \
|
||||||
right_commits[${#right_commits[@]}]="$comm"
|
right_commits[${#right_commits[@]}]="$comm"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ -n "$MISSING" -a ${#left_commits[@]} -eq 0 ]; then
|
if [ -n "$SINCELAST" -a ${#since_last[@]} -eq 0 ]; then
|
||||||
|
echo "No new commit upstream since last commit $last_bkp."
|
||||||
|
elif [ -n "$SINCELAST" ]; then
|
||||||
|
echo "Found ${#since_last[@]} commit(s) added to branch $REF since last backported commit $last_bkp:"
|
||||||
|
echo
|
||||||
|
echo " git cherry-pick -sx ${since_last[@]}"
|
||||||
|
echo
|
||||||
|
elif [ -n "$MISSING" -a ${#left_commits[@]} -eq 0 ]; then
|
||||||
echo "No missing commit to apply."
|
echo "No missing commit to apply."
|
||||||
elif [ -n "$MISSING" ]; then
|
elif [ -n "$MISSING" ]; then
|
||||||
echo
|
echo
|
||||||
|
|
|
||||||
123
src/acme.c
123
src/acme.c
|
|
@ -14,12 +14,8 @@
|
||||||
|
|
||||||
#include <haproxy/acme-t.h>
|
#include <haproxy/acme-t.h>
|
||||||
|
|
||||||
#include <haproxy/cli.h>
|
|
||||||
#include <haproxy/cfgparse.h>
|
|
||||||
#include <haproxy/errors.h>
|
|
||||||
#include <haproxy/jws.h>
|
|
||||||
|
|
||||||
#include <haproxy/base64.h>
|
#include <haproxy/base64.h>
|
||||||
|
#include <haproxy/intops.h>
|
||||||
#include <haproxy/cfgparse.h>
|
#include <haproxy/cfgparse.h>
|
||||||
#include <haproxy/cli.h>
|
#include <haproxy/cli.h>
|
||||||
#include <haproxy/errors.h>
|
#include <haproxy/errors.h>
|
||||||
|
|
@ -271,7 +267,6 @@ static int cfg_parse_acme(const char *file, int linenum, char **args, int kwm)
|
||||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
||||||
|
|
||||||
if (strcmp(args[0], "acme") == 0) {
|
if (strcmp(args[0], "acme") == 0) {
|
||||||
struct acme_cfg *tmp_acme = acme_cfgs;
|
|
||||||
|
|
||||||
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -297,7 +292,7 @@ static int cfg_parse_acme(const char *file, int linenum, char **args, int kwm)
|
||||||
* name */
|
* name */
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
ha_alert("parsing [%s:%d]: acme section '%s' already exists (%s:%d).\n",
|
ha_alert("parsing [%s:%d]: acme section '%s' already exists (%s:%d).\n",
|
||||||
file, linenum, args[1], tmp_acme->filename, tmp_acme->linenum);
|
file, linenum, args[1], cur_acme->filename, cur_acme->linenum);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -398,7 +393,7 @@ static int cfg_parse_acme_kws(char **args, int section_type, struct proxy *curpx
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (alertif_too_many_args(2, file, linenum, args, &err_code))
|
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ha_free(&cur_acme->account.file);
|
ha_free(&cur_acme->account.file);
|
||||||
|
|
@ -415,7 +410,7 @@ static int cfg_parse_acme_kws(char **args, int section_type, struct proxy *curpx
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alertif_too_many_args(2, file, linenum, args, &err_code))
|
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ha_free(&cur_acme->challenge);
|
ha_free(&cur_acme->challenge);
|
||||||
|
|
@ -883,7 +878,7 @@ static void acme_ctx_destroy(struct acme_ctx *ctx)
|
||||||
istfree(&auth->auth);
|
istfree(&auth->auth);
|
||||||
istfree(&auth->chall);
|
istfree(&auth->chall);
|
||||||
istfree(&auth->token);
|
istfree(&auth->token);
|
||||||
istfree(&auth->token);
|
istfree(&auth->dns);
|
||||||
next = auth->next;
|
next = auth->next;
|
||||||
free(auth);
|
free(auth);
|
||||||
auth = next;
|
auth = next;
|
||||||
|
|
@ -1193,7 +1188,7 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
}
|
}
|
||||||
/* get the next retry timing */
|
/* get the next retry timing */
|
||||||
if (isteqi(hdr->n, ist("Retry-After"))) {
|
if (isteqi(hdr->n, ist("Retry-After"))) {
|
||||||
ctx->retryafter = atol(hdr->v.ptr);
|
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1266,7 +1261,7 @@ int acme_res_chkorder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
}
|
}
|
||||||
/* get the next retry timing */
|
/* get the next retry timing */
|
||||||
if (isteqi(hdr->n, ist("Retry-After"))) {
|
if (isteqi(hdr->n, ist("Retry-After"))) {
|
||||||
ctx->retryafter = atol(hdr->v.ptr);
|
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1306,7 +1301,6 @@ int acme_res_chkorder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
goto error;
|
goto error;
|
||||||
};
|
};
|
||||||
|
|
||||||
out:
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
@ -1350,7 +1344,6 @@ int acme_req_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
csr->data = ret;
|
csr->data = ret;
|
||||||
|
|
||||||
chunk_printf(req_in, "{ \"csr\": \"%.*s\" }", (int)csr->data, csr->area);
|
chunk_printf(req_in, "{ \"csr\": \"%.*s\" }", (int)csr->data, csr->area);
|
||||||
OPENSSL_free(data);
|
|
||||||
|
|
||||||
|
|
||||||
if (acme_jws_payload(req_in, ctx->nonce, ctx->finalize, ctx->cfg->account.pkey, ctx->kid, req_out, errmsg) != 0)
|
if (acme_jws_payload(req_in, ctx->nonce, ctx->finalize, ctx->cfg->account.pkey, ctx->kid, req_out, errmsg) != 0)
|
||||||
|
|
@ -1359,11 +1352,12 @@ int acme_req_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
if (acme_http_req(task, ctx, ctx->finalize, HTTP_METH_POST, hdrs, ist2(req_out->area, req_out->data)))
|
if (acme_http_req(task, ctx, ctx->finalize, HTTP_METH_POST, hdrs, ist2(req_out->area, req_out->data)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
error:
|
error:
|
||||||
memprintf(errmsg, "couldn't request the finalize URL");
|
memprintf(errmsg, "couldn't request the finalize URL");
|
||||||
|
out:
|
||||||
|
OPENSSL_free(data);
|
||||||
free_trash_chunk(req_in);
|
free_trash_chunk(req_in);
|
||||||
free_trash_chunk(req_out);
|
free_trash_chunk(req_out);
|
||||||
free_trash_chunk(csr);
|
free_trash_chunk(csr);
|
||||||
|
|
@ -1397,7 +1391,7 @@ int acme_res_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
}
|
}
|
||||||
/* get the next retry timing */
|
/* get the next retry timing */
|
||||||
if (isteqi(hdr->n, ist("Retry-After"))) {
|
if (isteqi(hdr->n, ist("Retry-After"))) {
|
||||||
ctx->retryafter = atol(hdr->v.ptr);
|
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1415,7 +1409,7 @@ int acme_res_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
memprintf(errmsg, "invalid HTTP status code %d when getting Finalize URL", hc->res.status);
|
memprintf(errmsg, "invalid HTTP status code %d when getting Finalize URL", hc->res.status);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
@ -1458,9 +1452,10 @@ int acme_req_challenge(struct task *task, struct acme_ctx *ctx, struct acme_auth
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
error:
|
error:
|
||||||
memprintf(errmsg, "couldn't generate the Challenge request");
|
memprintf(errmsg, "couldn't generate the Challenge request");
|
||||||
|
out:
|
||||||
free_trash_chunk(req_in);
|
free_trash_chunk(req_in);
|
||||||
free_trash_chunk(req_out);
|
free_trash_chunk(req_out);
|
||||||
|
|
||||||
|
|
@ -1497,7 +1492,7 @@ enum acme_ret acme_res_challenge(struct task *task, struct acme_ctx *ctx, struct
|
||||||
}
|
}
|
||||||
/* get the next retry timing */
|
/* get the next retry timing */
|
||||||
if (isteqi(hdr->n, ist("Retry-After"))) {
|
if (isteqi(hdr->n, ist("Retry-After"))) {
|
||||||
ctx->retryafter = atol(hdr->v.ptr);
|
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1576,6 +1571,8 @@ int acme_post_as_get(struct task *task, struct acme_ctx *ctx, struct ist url, ch
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
|
||||||
error_jws:
|
error_jws:
|
||||||
memprintf(errmsg, "couldn't generate the JWS token: %s", errmsg ? *errmsg : "");
|
memprintf(errmsg, "couldn't generate the JWS token: %s", errmsg ? *errmsg : "");
|
||||||
goto end;
|
goto end;
|
||||||
|
|
@ -1621,7 +1618,7 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
|
||||||
}
|
}
|
||||||
/* get the next retry timing */
|
/* get the next retry timing */
|
||||||
if (isteqi(hdr->n, ist("Retry-After"))) {
|
if (isteqi(hdr->n, ist("Retry-After"))) {
|
||||||
ctx->retryafter = atol(hdr->v.ptr);
|
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1657,6 +1654,19 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
|
||||||
|
|
||||||
auth->dns = istdup(ist2(t2->area, t2->data));
|
auth->dns = istdup(ist2(t2->area, t2->data));
|
||||||
|
|
||||||
|
ret = mjson_get_string(hc->res.buf.area, hc->res.buf.data, "$.status", trash.area, trash.size);
|
||||||
|
if (ret == -1) {
|
||||||
|
memprintf(errmsg, "couldn't get a \"status\" from Authorization URL \"%s\"", auth->auth.ptr);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
trash.data = ret;
|
||||||
|
|
||||||
|
/* if auth is already valid we need to skip solving challenges */
|
||||||
|
if (strncasecmp("valid", trash.area, trash.data) == 0) {
|
||||||
|
auth->validated = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* get the multiple challenges and select the one from the configuration */
|
/* get the multiple challenges and select the one from the configuration */
|
||||||
for (i = 0; ; i++) {
|
for (i = 0; ; i++) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -1816,9 +1826,10 @@ int acme_req_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
error:
|
error:
|
||||||
memprintf(errmsg, "couldn't generate the newOrder request");
|
memprintf(errmsg, "couldn't generate the newOrder request");
|
||||||
|
out:
|
||||||
free_trash_chunk(req_in);
|
free_trash_chunk(req_in);
|
||||||
free_trash_chunk(req_out);
|
free_trash_chunk(req_out);
|
||||||
|
|
||||||
|
|
@ -1852,7 +1863,7 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
}
|
}
|
||||||
/* get the next retry timing */
|
/* get the next retry timing */
|
||||||
if (isteqi(hdr->n, ist("Retry-After"))) {
|
if (isteqi(hdr->n, ist("Retry-After"))) {
|
||||||
ctx->retryafter = atol(hdr->v.ptr);
|
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
|
||||||
}
|
}
|
||||||
/* get the order URL */
|
/* get the order URL */
|
||||||
if (isteqi(hdr->n, ist("Location"))) {
|
if (isteqi(hdr->n, ist("Location"))) {
|
||||||
|
|
@ -1926,7 +1937,6 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
@ -1978,9 +1988,10 @@ int acme_req_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
error:
|
error:
|
||||||
memprintf(errmsg, "couldn't generate the newAccount request");
|
memprintf(errmsg, "couldn't generate the newAccount request");
|
||||||
|
out:
|
||||||
free_trash_chunk(req_in);
|
free_trash_chunk(req_in);
|
||||||
free_trash_chunk(req_out);
|
free_trash_chunk(req_out);
|
||||||
|
|
||||||
|
|
@ -2012,7 +2023,7 @@ int acme_res_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch
|
||||||
}
|
}
|
||||||
/* get the next retry timing */
|
/* get the next retry timing */
|
||||||
if (isteqi(hdr->n, ist("Retry-After"))) {
|
if (isteqi(hdr->n, ist("Retry-After"))) {
|
||||||
ctx->retryafter = atol(hdr->v.ptr);
|
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
|
||||||
}
|
}
|
||||||
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
||||||
istfree(&ctx->nonce);
|
istfree(&ctx->nonce);
|
||||||
|
|
@ -2266,6 +2277,14 @@ re:
|
||||||
break;
|
break;
|
||||||
case ACME_CHALLENGE:
|
case ACME_CHALLENGE:
|
||||||
if (http_st == ACME_HTTP_REQ) {
|
if (http_st == ACME_HTTP_REQ) {
|
||||||
|
/* if challenge is already validated we skip this stage */
|
||||||
|
if (ctx->next_auth->validated) {
|
||||||
|
if ((ctx->next_auth = ctx->next_auth->next) == NULL) {
|
||||||
|
st = ACME_CHKCHALLENGE;
|
||||||
|
ctx->next_auth = ctx->auths;
|
||||||
|
}
|
||||||
|
goto nextreq;
|
||||||
|
}
|
||||||
|
|
||||||
/* if the challenge is not ready, wait to be wakeup */
|
/* if the challenge is not ready, wait to be wakeup */
|
||||||
if (!ctx->next_auth->ready)
|
if (!ctx->next_auth->ready)
|
||||||
|
|
@ -2295,6 +2314,14 @@ re:
|
||||||
break;
|
break;
|
||||||
case ACME_CHKCHALLENGE:
|
case ACME_CHKCHALLENGE:
|
||||||
if (http_st == ACME_HTTP_REQ) {
|
if (http_st == ACME_HTTP_REQ) {
|
||||||
|
/* if challenge is already validated we skip this stage */
|
||||||
|
if (ctx->next_auth->validated) {
|
||||||
|
if ((ctx->next_auth = ctx->next_auth->next) == NULL)
|
||||||
|
st = ACME_FINALIZE;
|
||||||
|
|
||||||
|
goto nextreq;
|
||||||
|
}
|
||||||
|
|
||||||
if (acme_post_as_get(task, ctx, ctx->next_auth->chall, &errmsg) != 0)
|
if (acme_post_as_get(task, ctx, ctx->next_auth->chall, &errmsg) != 0)
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
@ -2529,9 +2556,9 @@ X509_REQ *acme_x509_req(EVP_PKEY *pkey, char **san)
|
||||||
{
|
{
|
||||||
struct buffer *san_trash = NULL;
|
struct buffer *san_trash = NULL;
|
||||||
X509_REQ *x = NULL;
|
X509_REQ *x = NULL;
|
||||||
X509_NAME *nm;
|
X509_NAME *nm = NULL;
|
||||||
STACK_OF(X509_EXTENSION) *exts = NULL;
|
STACK_OF(X509_EXTENSION) *exts = NULL;
|
||||||
X509_EXTENSION *ext_san;
|
X509_EXTENSION *ext_san = NULL;
|
||||||
char *str_san = NULL;
|
char *str_san = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
|
@ -2562,26 +2589,36 @@ X509_REQ *acme_x509_req(EVP_PKEY *pkey, char **san)
|
||||||
for (i = 0; san[i]; i++) {
|
for (i = 0; san[i]; i++) {
|
||||||
chunk_appendf(san_trash, "%sDNS:%s", i ? "," : "", san[i]);
|
chunk_appendf(san_trash, "%sDNS:%s", i ? "," : "", san[i]);
|
||||||
}
|
}
|
||||||
str_san = my_strndup(san_trash->area, san_trash->data);
|
if ((str_san = my_strndup(san_trash->area, san_trash->data)) == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if ((ext_san = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, str_san)) == NULL)
|
if ((ext_san = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, str_san)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!sk_X509_EXTENSION_push(exts, ext_san))
|
if (!sk_X509_EXTENSION_push(exts, ext_san))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
ext_san = NULL; /* handle double-free upon error */
|
||||||
|
|
||||||
if (!X509_REQ_add_extensions(x, exts))
|
if (!X509_REQ_add_extensions(x, exts))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
|
|
||||||
|
|
||||||
if (!X509_REQ_sign(x, pkey, EVP_sha256()))
|
if (!X509_REQ_sign(x, pkey, EVP_sha256()))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
|
||||||
|
X509_NAME_free(nm);
|
||||||
|
free(str_san);
|
||||||
free_trash_chunk(san_trash);
|
free_trash_chunk(san_trash);
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
X509_EXTENSION_free(ext_san);
|
||||||
|
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
|
||||||
|
X509_REQ_free(x);
|
||||||
|
X509_NAME_free(nm);
|
||||||
|
free(str_san);
|
||||||
free_trash_chunk(san_trash);
|
free_trash_chunk(san_trash);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
@ -2630,7 +2667,7 @@ EVP_PKEY *acme_gen_tmp_pkey()
|
||||||
/* start an ACME task */
|
/* start an ACME task */
|
||||||
static int acme_start_task(struct ckch_store *store, char **errmsg)
|
static int acme_start_task(struct ckch_store *store, char **errmsg)
|
||||||
{
|
{
|
||||||
struct task *task;
|
struct task *task = NULL;
|
||||||
struct acme_ctx *ctx = NULL;
|
struct acme_ctx *ctx = NULL;
|
||||||
struct acme_cfg *cfg;
|
struct acme_cfg *cfg;
|
||||||
struct ckch_store *newstore = NULL;
|
struct ckch_store *newstore = NULL;
|
||||||
|
|
@ -2715,6 +2752,8 @@ err:
|
||||||
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &acme_lock);
|
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &acme_lock);
|
||||||
acme_ctx_destroy(ctx);
|
acme_ctx_destroy(ctx);
|
||||||
}
|
}
|
||||||
|
if (task)
|
||||||
|
task_destroy(task);
|
||||||
memprintf(errmsg, "%sCan't start the ACME client.", *errmsg ? *errmsg : "");
|
memprintf(errmsg, "%sCan't start the ACME client.", *errmsg ? *errmsg : "");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -2724,7 +2763,10 @@ static int cli_acme_renew_parse(char **args, char *payload, struct appctx *appct
|
||||||
struct ckch_store *store = NULL;
|
struct ckch_store *store = NULL;
|
||||||
char *errmsg = NULL;
|
char *errmsg = NULL;
|
||||||
|
|
||||||
if (!*args[1]) {
|
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!*args[2]) {
|
||||||
memprintf(&errmsg, ": not enough parameters\n");
|
memprintf(&errmsg, ": not enough parameters\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
@ -2763,8 +2805,11 @@ static int cli_acme_chall_ready_parse(char **args, char *payload, struct appctx
|
||||||
int remain = 0;
|
int remain = 0;
|
||||||
struct ebmb_node *node = NULL;
|
struct ebmb_node *node = NULL;
|
||||||
|
|
||||||
if (!*args[2] && !*args[3] && !*args[4]) {
|
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
|
||||||
memprintf(&msg, ": not enough parameters\n");
|
return 1;
|
||||||
|
|
||||||
|
if (!*args[2] || !*args[3] || !*args[4]) {
|
||||||
|
memprintf(&msg, "Not enough parameters: \"acme challenge_ready <certfile> domain <domain>\"\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2885,8 +2930,12 @@ end:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cli_acme_ps(char **args, char *payload, struct appctx *appctx, void *private)
|
static int cli_acme_parse_status(char **args, char *payload, struct appctx *appctx, void *private)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
|
||||||
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2894,7 +2943,7 @@ static int cli_acme_ps(char **args, char *payload, struct appctx *appctx, void *
|
||||||
|
|
||||||
static struct cli_kw_list cli_kws = {{ },{
|
static struct cli_kw_list cli_kws = {{ },{
|
||||||
{ { "acme", "renew", NULL }, "acme renew <certfile> : renew a certificate using the ACME protocol", cli_acme_renew_parse, NULL, NULL, NULL, 0 },
|
{ { "acme", "renew", NULL }, "acme renew <certfile> : renew a certificate using the ACME protocol", cli_acme_renew_parse, NULL, NULL, NULL, 0 },
|
||||||
{ { "acme", "status", NULL }, "acme status : show status of certificates configured with ACME", cli_acme_ps, cli_acme_status_io_handler, NULL, NULL, 0 },
|
{ { "acme", "status", NULL }, "acme status : show status of certificates configured with ACME", cli_acme_parse_status, cli_acme_status_io_handler, NULL, NULL, 0 },
|
||||||
{ { "acme", "challenge_ready", NULL }, "acme challenge_ready <certfile> domain <domain> : notify HAProxy that the ACME challenge is ready", cli_acme_chall_ready_parse, NULL, NULL, NULL, 0 },
|
{ { "acme", "challenge_ready", NULL }, "acme challenge_ready <certfile> domain <domain> : notify HAProxy that the ACME challenge is ready", cli_acme_chall_ready_parse, NULL, NULL, NULL, 0 },
|
||||||
{ { NULL }, NULL, NULL, NULL }
|
{ { NULL }, NULL, NULL, NULL }
|
||||||
}};
|
}};
|
||||||
|
|
|
||||||
31
src/action.c
31
src/action.c
|
|
@ -25,7 +25,8 @@
|
||||||
|
|
||||||
|
|
||||||
/* Check an action ruleset validity. It returns the number of error encountered
|
/* Check an action ruleset validity. It returns the number of error encountered
|
||||||
* and err_code is updated if a warning is emitted.
|
* and err_code is updated if a warning is emitted. It also takes this
|
||||||
|
* opportunity for filling the execution context based on available info.
|
||||||
*/
|
*/
|
||||||
int check_action_rules(struct list *rules, struct proxy *px, int *err_code)
|
int check_action_rules(struct list *rules, struct proxy *px, int *err_code)
|
||||||
{
|
{
|
||||||
|
|
@ -40,6 +41,13 @@ int check_action_rules(struct list *rules, struct proxy *px, int *err_code)
|
||||||
}
|
}
|
||||||
*err_code |= warnif_tcp_http_cond(px, rule->cond);
|
*err_code |= warnif_tcp_http_cond(px, rule->cond);
|
||||||
ha_free(&errmsg);
|
ha_free(&errmsg);
|
||||||
|
|
||||||
|
if (!rule->exec_ctx.type) {
|
||||||
|
if (rule->kw && rule->kw->exec_ctx.type)
|
||||||
|
rule->exec_ctx = rule->kw->exec_ctx;
|
||||||
|
else if (rule->action_ptr)
|
||||||
|
rule->exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FUNC, rule->action_ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -378,3 +386,24 @@ void dump_act_rules(const struct list *rules, const char *pfx)
|
||||||
(akwn->flags & KWF_MATCH_PREFIX) ? "*" : "");
|
(akwn->flags & KWF_MATCH_PREFIX) ? "*" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* adds the keyword list kw_list to the head <head> */
|
||||||
|
void act_add_list(struct list *head, struct action_kw_list *kw_list)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; kw_list->kw[i].kw != NULL; i++) {
|
||||||
|
/* store declaration file/line if known */
|
||||||
|
if (kw_list->kw[i].exec_ctx.type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (caller_initcall) {
|
||||||
|
kw_list->kw[i].exec_ctx.type = TH_EX_CTX_INITCALL;
|
||||||
|
kw_list->kw[i].exec_ctx.initcall = caller_initcall;
|
||||||
|
} else {
|
||||||
|
kw_list->kw[i].exec_ctx.type = TH_EX_CTX_ACTION;
|
||||||
|
kw_list->kw[i].exec_ctx.action_kwl = kw_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LIST_APPEND(head, &kw_list->list);
|
||||||
|
}
|
||||||
|
|
|
||||||
156
src/activity.c
156
src/activity.c
|
|
@ -29,8 +29,11 @@ struct show_prof_ctx {
|
||||||
int dump_step; /* 0,1,2,4,5,6; see cli_iohandler_show_profiling() */
|
int dump_step; /* 0,1,2,4,5,6; see cli_iohandler_show_profiling() */
|
||||||
int linenum; /* next line to be dumped (starts at 0) */
|
int linenum; /* next line to be dumped (starts at 0) */
|
||||||
int maxcnt; /* max line count per step (0=not set) */
|
int maxcnt; /* max line count per step (0=not set) */
|
||||||
int by_what; /* 0=sort by usage, 1=sort by address, 2=sort by time */
|
int by_what; /* 0=sort by usage, 1=sort by address, 2=sort by time, 3=sort by ctx */
|
||||||
int aggr; /* 0=dump raw, 1=aggregate on callee */
|
int aggr; /* 0=dump raw, 1=aggregate on callee */
|
||||||
|
/* 4-byte hole here */
|
||||||
|
struct sched_activity *tmp_activity; /* dynamically allocated during dumps */
|
||||||
|
struct memprof_stats *tmp_memstats; /* dynamically allocated during dumps */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* CLI context for the "show activity" command */
|
/* CLI context for the "show activity" command */
|
||||||
|
|
@ -299,13 +302,18 @@ struct memprof_stats *memprof_get_bin(const void *ra, enum memprof_method meth)
|
||||||
int retries = 16; // up to 16 consecutive entries may be tested.
|
int retries = 16; // up to 16 consecutive entries may be tested.
|
||||||
const void *old;
|
const void *old;
|
||||||
unsigned int bin;
|
unsigned int bin;
|
||||||
|
ullong hash;
|
||||||
|
|
||||||
if (unlikely(!ra)) {
|
if (unlikely(!ra)) {
|
||||||
bin = MEMPROF_HASH_BUCKETS;
|
bin = MEMPROF_HASH_BUCKETS;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
bin = ptr_hash(ra, MEMPROF_HASH_BITS);
|
hash = _ptr2_hash_arg(ra, th_ctx->exec_ctx.pointer, th_ctx->exec_ctx.type);
|
||||||
for (; memprof_stats[bin].caller != ra; bin = (bin + 1) & (MEMPROF_HASH_BUCKETS - 1)) {
|
for (bin = _ptr_hash_reduce(hash, MEMPROF_HASH_BITS);
|
||||||
|
memprof_stats[bin].caller != ra ||
|
||||||
|
memprof_stats[bin].exec_ctx.type != th_ctx->exec_ctx.type ||
|
||||||
|
memprof_stats[bin].exec_ctx.pointer != th_ctx->exec_ctx.pointer;
|
||||||
|
bin = (bin + (hash | 1)) & (MEMPROF_HASH_BUCKETS - 1)) {
|
||||||
if (!--retries) {
|
if (!--retries) {
|
||||||
bin = MEMPROF_HASH_BUCKETS;
|
bin = MEMPROF_HASH_BUCKETS;
|
||||||
break;
|
break;
|
||||||
|
|
@ -314,6 +322,7 @@ struct memprof_stats *memprof_get_bin(const void *ra, enum memprof_method meth)
|
||||||
old = NULL;
|
old = NULL;
|
||||||
if (!memprof_stats[bin].caller &&
|
if (!memprof_stats[bin].caller &&
|
||||||
HA_ATOMIC_CAS(&memprof_stats[bin].caller, &old, ra)) {
|
HA_ATOMIC_CAS(&memprof_stats[bin].caller, &old, ra)) {
|
||||||
|
memprof_stats[bin].exec_ctx = th_ctx->exec_ctx;
|
||||||
memprof_stats[bin].method = meth;
|
memprof_stats[bin].method = meth;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -918,6 +927,14 @@ static int cmp_memprof_stats(const void *a, const void *b)
|
||||||
return -1;
|
return -1;
|
||||||
else if (l->alloc_tot + l->free_tot < r->alloc_tot + r->free_tot)
|
else if (l->alloc_tot + l->free_tot < r->alloc_tot + r->free_tot)
|
||||||
return 1;
|
return 1;
|
||||||
|
else if (l->exec_ctx.type > r->exec_ctx.type)
|
||||||
|
return -1;
|
||||||
|
else if (l->exec_ctx.type < r->exec_ctx.type)
|
||||||
|
return 1;
|
||||||
|
else if (l->exec_ctx.pointer > r->exec_ctx.pointer)
|
||||||
|
return -1;
|
||||||
|
else if (l->exec_ctx.pointer < r->exec_ctx.pointer)
|
||||||
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -931,6 +948,47 @@ static int cmp_memprof_addr(const void *a, const void *b)
|
||||||
return -1;
|
return -1;
|
||||||
else if (l->caller < r->caller)
|
else if (l->caller < r->caller)
|
||||||
return 1;
|
return 1;
|
||||||
|
else if (l->exec_ctx.type > r->exec_ctx.type)
|
||||||
|
return -1;
|
||||||
|
else if (l->exec_ctx.type < r->exec_ctx.type)
|
||||||
|
return 1;
|
||||||
|
else if (l->exec_ctx.pointer > r->exec_ctx.pointer)
|
||||||
|
return -1;
|
||||||
|
else if (l->exec_ctx.pointer < r->exec_ctx.pointer)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_memprof_ctx(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct memprof_stats *l = (const struct memprof_stats *)a;
|
||||||
|
const struct memprof_stats *r = (const struct memprof_stats *)b;
|
||||||
|
const void *ptrl = l->exec_ctx.pointer;
|
||||||
|
const void *ptrr = r->exec_ctx.pointer;
|
||||||
|
|
||||||
|
/* in case of a mux, we'll use the always-present ->subscribe()
|
||||||
|
* function as a sorting key so that mux-ops and other mux functions
|
||||||
|
* appear grouped together.
|
||||||
|
*/
|
||||||
|
if (l->exec_ctx.type == TH_EX_CTX_MUX)
|
||||||
|
ptrl = l->exec_ctx.mux_ops->subscribe;
|
||||||
|
|
||||||
|
if (r->exec_ctx.type == TH_EX_CTX_MUX)
|
||||||
|
ptrr = r->exec_ctx.mux_ops->subscribe;
|
||||||
|
|
||||||
|
if (ptrl > ptrr)
|
||||||
|
return -1;
|
||||||
|
else if (ptrl < ptrr)
|
||||||
|
return 1;
|
||||||
|
else if (l->exec_ctx.type > r->exec_ctx.type)
|
||||||
|
return -1;
|
||||||
|
else if (l->exec_ctx.type < r->exec_ctx.type)
|
||||||
|
return 1;
|
||||||
|
else if (l->caller > r->caller)
|
||||||
|
return -1;
|
||||||
|
else if (l->caller < r->caller)
|
||||||
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -992,9 +1050,9 @@ struct sched_activity *sched_activity_entry(struct sched_activity *array, const
|
||||||
static int cli_io_handler_show_profiling(struct appctx *appctx)
|
static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
{
|
{
|
||||||
struct show_prof_ctx *ctx = appctx->svcctx;
|
struct show_prof_ctx *ctx = appctx->svcctx;
|
||||||
struct sched_activity tmp_activity[SCHED_ACT_HASH_BUCKETS];
|
struct sched_activity *tmp_activity = ctx->tmp_activity;
|
||||||
#ifdef USE_MEMORY_PROFILING
|
#ifdef USE_MEMORY_PROFILING
|
||||||
struct memprof_stats tmp_memstats[MEMPROF_HASH_BUCKETS + 1];
|
struct memprof_stats *tmp_memstats = ctx->tmp_memstats;
|
||||||
unsigned long long tot_alloc_calls, tot_free_calls;
|
unsigned long long tot_alloc_calls, tot_free_calls;
|
||||||
unsigned long long tot_alloc_bytes, tot_free_bytes;
|
unsigned long long tot_alloc_bytes, tot_free_bytes;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1035,7 +1093,20 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
if ((ctx->dump_step & 3) != 1)
|
if ((ctx->dump_step & 3) != 1)
|
||||||
goto skip_tasks;
|
goto skip_tasks;
|
||||||
|
|
||||||
memcpy(tmp_activity, sched_activity, sizeof(tmp_activity));
|
if (tmp_activity)
|
||||||
|
goto tasks_resume;
|
||||||
|
|
||||||
|
/* first call for show profiling tasks: we have to allocate a tmp
|
||||||
|
* array for sorting and processing, and possibly perform some
|
||||||
|
* sorting and aggregation.
|
||||||
|
*/
|
||||||
|
tmp_activity = ha_aligned_alloc(__alignof__(*tmp_activity), sizeof(sched_activity));
|
||||||
|
if (!tmp_activity)
|
||||||
|
goto end_tasks;
|
||||||
|
|
||||||
|
ctx->tmp_activity = tmp_activity;
|
||||||
|
memcpy(tmp_activity, sched_activity, sizeof(sched_activity));
|
||||||
|
|
||||||
/* for addr sort and for callee aggregation we have to first sort by address */
|
/* for addr sort and for callee aggregation we have to first sort by address */
|
||||||
if (ctx->aggr || ctx->by_what == 1) // sort by addr
|
if (ctx->aggr || ctx->by_what == 1) // sort by addr
|
||||||
qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_addr);
|
qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_addr);
|
||||||
|
|
@ -1060,6 +1131,7 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
else if (ctx->by_what == 2) // by cpu_tot
|
else if (ctx->by_what == 2) // by cpu_tot
|
||||||
qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_cpu);
|
qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_cpu);
|
||||||
|
|
||||||
|
tasks_resume:
|
||||||
if (!ctx->linenum)
|
if (!ctx->linenum)
|
||||||
chunk_appendf(&trash, "Tasks activity over %.3f sec till %.3f sec ago:\n"
|
chunk_appendf(&trash, "Tasks activity over %.3f sec till %.3f sec ago:\n"
|
||||||
" function calls cpu_tot cpu_avg lkw_avg lkd_avg mem_avg lat_avg\n",
|
" function calls cpu_tot cpu_avg lkw_avg lkd_avg mem_avg lat_avg\n",
|
||||||
|
|
@ -1123,6 +1195,8 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end_tasks:
|
||||||
|
ha_free(&ctx->tmp_activity);
|
||||||
ctx->linenum = 0; // reset first line to dump
|
ctx->linenum = 0; // reset first line to dump
|
||||||
if ((ctx->dump_step & 4) == 0)
|
if ((ctx->dump_step & 4) == 0)
|
||||||
ctx->dump_step++; // next step
|
ctx->dump_step++; // next step
|
||||||
|
|
@ -1133,16 +1207,57 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
if ((ctx->dump_step & 3) != 2)
|
if ((ctx->dump_step & 3) != 2)
|
||||||
goto skip_mem;
|
goto skip_mem;
|
||||||
|
|
||||||
memcpy(tmp_memstats, memprof_stats, sizeof(tmp_memstats));
|
if (tmp_memstats)
|
||||||
if (ctx->by_what)
|
goto memstats_resume;
|
||||||
|
|
||||||
|
/* first call for show profiling memory: we have to allocate a tmp
|
||||||
|
* array for sorting and processing, and possibly perform some sorting
|
||||||
|
* and aggregation.
|
||||||
|
*/
|
||||||
|
tmp_memstats = ha_aligned_alloc(__alignof__(*tmp_memstats), sizeof(memprof_stats));
|
||||||
|
if (!tmp_memstats)
|
||||||
|
goto end_memstats;
|
||||||
|
|
||||||
|
ctx->tmp_memstats = tmp_memstats;
|
||||||
|
memcpy(tmp_memstats, memprof_stats, sizeof(memprof_stats));
|
||||||
|
|
||||||
|
if (ctx->by_what == 1)
|
||||||
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_addr);
|
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_addr);
|
||||||
|
else if (ctx->by_what == 3)
|
||||||
|
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_ctx);
|
||||||
else
|
else
|
||||||
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_stats);
|
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_stats);
|
||||||
|
|
||||||
|
if (ctx->aggr) {
|
||||||
|
/* merge entries for the same caller and reset the exec_ctx */
|
||||||
|
for (i = j = 0; i < MEMPROF_HASH_BUCKETS; i++) {
|
||||||
|
if ((tmp_memstats[i].alloc_calls | tmp_memstats[i].free_calls) == 0)
|
||||||
|
continue;
|
||||||
|
for (j = i + 1; j < MEMPROF_HASH_BUCKETS; j++) {
|
||||||
|
if ((tmp_memstats[j].alloc_calls | tmp_memstats[j].free_calls) == 0)
|
||||||
|
continue;
|
||||||
|
if (tmp_memstats[j].caller != tmp_memstats[i].caller ||
|
||||||
|
tmp_memstats[j].method != tmp_memstats[i].method ||
|
||||||
|
tmp_memstats[j].info != tmp_memstats[i].info)
|
||||||
|
continue;
|
||||||
|
tmp_memstats[i].locked_calls += tmp_memstats[j].locked_calls;
|
||||||
|
tmp_memstats[i].alloc_calls += tmp_memstats[j].alloc_calls;
|
||||||
|
tmp_memstats[i].free_calls += tmp_memstats[j].free_calls;
|
||||||
|
tmp_memstats[i].alloc_tot += tmp_memstats[j].alloc_tot;
|
||||||
|
tmp_memstats[i].free_tot += tmp_memstats[j].free_tot;
|
||||||
|
/* don't dump the ctx */
|
||||||
|
tmp_memstats[i].exec_ctx.type = 0;
|
||||||
|
/* don't dump the merged entry */
|
||||||
|
tmp_memstats[j].alloc_calls = tmp_memstats[j].free_calls = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memstats_resume:
|
||||||
if (!ctx->linenum)
|
if (!ctx->linenum)
|
||||||
chunk_appendf(&trash,
|
chunk_appendf(&trash,
|
||||||
"Alloc/Free statistics by call place over %.3f sec till %.3f sec ago:\n"
|
"Alloc/Free statistics by call place over %.3f sec till %.3f sec ago:\n"
|
||||||
" Calls | Tot Bytes | Caller and method\n"
|
" Calls | Tot Bytes | Caller, method, extra info\n"
|
||||||
"<- alloc -> <- free ->|<-- alloc ---> <-- free ---->|\n",
|
"<- alloc -> <- free ->|<-- alloc ---> <-- free ---->|\n",
|
||||||
(prof_mem_start_ns ? (prof_mem_stop_ns ? prof_mem_stop_ns : now_ns) - prof_mem_start_ns : 0) / 1000000000.0,
|
(prof_mem_start_ns ? (prof_mem_stop_ns ? prof_mem_stop_ns : now_ns) - prof_mem_start_ns : 0) / 1000000000.0,
|
||||||
(prof_mem_stop_ns ? now_ns - prof_mem_stop_ns : 0) / 1000000000.0);
|
(prof_mem_stop_ns ? now_ns - prof_mem_stop_ns : 0) / 1000000000.0);
|
||||||
|
|
@ -1200,6 +1315,7 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
(int)((1000ULL * entry->locked_calls / tot_calls) % 10));
|
(int)((1000ULL * entry->locked_calls / tot_calls) % 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk_append_thread_ctx(&trash, &entry->exec_ctx, " [via ", "]");
|
||||||
chunk_appendf(&trash, "\n");
|
chunk_appendf(&trash, "\n");
|
||||||
|
|
||||||
if (applet_putchk(appctx, &trash) == -1)
|
if (applet_putchk(appctx, &trash) == -1)
|
||||||
|
|
@ -1309,9 +1425,15 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
tot_alloc_calls - tot_free_calls,
|
tot_alloc_calls - tot_free_calls,
|
||||||
tot_alloc_bytes - tot_free_bytes);
|
tot_alloc_bytes - tot_free_bytes);
|
||||||
|
|
||||||
|
/* release optional buffer name */
|
||||||
|
for (i = 0; i < max; i++)
|
||||||
|
ha_free(&tmp_memstats[i].info);
|
||||||
|
|
||||||
if (applet_putchk(appctx, &trash) == -1)
|
if (applet_putchk(appctx, &trash) == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
end_memstats:
|
||||||
|
ha_free(&ctx->tmp_memstats);
|
||||||
ctx->linenum = 0; // reset first line to dump
|
ctx->linenum = 0; // reset first line to dump
|
||||||
if ((ctx->dump_step & 4) == 0)
|
if ((ctx->dump_step & 4) == 0)
|
||||||
ctx->dump_step++; // next step
|
ctx->dump_step++; // next step
|
||||||
|
|
@ -1322,6 +1444,15 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* release structs allocated by "show profiling" */
|
||||||
|
static void cli_release_show_profiling(struct appctx *appctx)
|
||||||
|
{
|
||||||
|
struct show_prof_ctx *ctx = appctx->svcctx;
|
||||||
|
|
||||||
|
ha_free(&ctx->tmp_activity);
|
||||||
|
ha_free(&ctx->tmp_memstats);
|
||||||
|
}
|
||||||
|
|
||||||
/* parse a "show profiling" command. It returns 1 on failure, 0 if it starts to dump.
|
/* parse a "show profiling" command. It returns 1 on failure, 0 if it starts to dump.
|
||||||
* - cli.i0 is set to the first state (0=all, 4=status, 5=tasks, 6=memory)
|
* - cli.i0 is set to the first state (0=all, 4=status, 5=tasks, 6=memory)
|
||||||
* - cli.o1 is set to 1 if the output must be sorted by addr instead of usage
|
* - cli.o1 is set to 1 if the output must be sorted by addr instead of usage
|
||||||
|
|
@ -1354,6 +1485,9 @@ static int cli_parse_show_profiling(char **args, char *payload, struct appctx *a
|
||||||
else if (strcmp(args[arg], "bytime") == 0) {
|
else if (strcmp(args[arg], "bytime") == 0) {
|
||||||
ctx->by_what = 2; // sort output by total time instead of usage
|
ctx->by_what = 2; // sort output by total time instead of usage
|
||||||
}
|
}
|
||||||
|
else if (strcmp(args[arg], "byctx") == 0) {
|
||||||
|
ctx->by_what = 3; // sort output by caller context instead of usage
|
||||||
|
}
|
||||||
else if (strcmp(args[arg], "aggr") == 0) {
|
else if (strcmp(args[arg], "aggr") == 0) {
|
||||||
ctx->aggr = 1; // aggregate output by callee
|
ctx->aggr = 1; // aggregate output by callee
|
||||||
}
|
}
|
||||||
|
|
@ -1361,7 +1495,7 @@ static int cli_parse_show_profiling(char **args, char *payload, struct appctx *a
|
||||||
ctx->maxcnt = atoi(args[arg]); // number of entries to dump
|
ctx->maxcnt = atoi(args[arg]); // number of entries to dump
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return cli_err(appctx, "Expects either 'all', 'status', 'tasks', 'memory', 'byaddr', 'bytime', 'aggr' or a max number of output lines.\n");
|
return cli_err(appctx, "Expects either 'all', 'status', 'tasks', 'memory', 'byaddr', 'bytime', 'byctx', 'aggr' or a max number of output lines.\n");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1705,7 +1839,7 @@ INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
|
||||||
static struct cli_kw_list cli_kws = {{ },{
|
static struct cli_kw_list cli_kws = {{ },{
|
||||||
{ { "set", "profiling", NULL }, "set profiling <what> {auto|on|off} : enable/disable resource profiling (tasks,memory)", cli_parse_set_profiling, NULL },
|
{ { "set", "profiling", NULL }, "set profiling <what> {auto|on|off} : enable/disable resource profiling (tasks,memory)", cli_parse_set_profiling, NULL },
|
||||||
{ { "show", "activity", NULL }, "show activity [-1|0|thread_num] : show per-thread activity stats (for support/developers)", cli_parse_show_activity, cli_io_handler_show_activity, NULL },
|
{ { "show", "activity", NULL }, "show activity [-1|0|thread_num] : show per-thread activity stats (for support/developers)", cli_parse_show_activity, cli_io_handler_show_activity, NULL },
|
||||||
{ { "show", "profiling", NULL }, "show profiling [<what>|<#lines>|<opts>]*: show profiling state (all,status,tasks,memory)", cli_parse_show_profiling, cli_io_handler_show_profiling, NULL },
|
{ { "show", "profiling", NULL }, "show profiling [<what>|<#lines>|<opts>]*: show profiling state (all,status,tasks,memory)", cli_parse_show_profiling, cli_io_handler_show_profiling, cli_release_show_profiling },
|
||||||
{ { "show", "tasks", NULL }, "show tasks : show running tasks", NULL, cli_io_handler_show_tasks, NULL },
|
{ { "show", "tasks", NULL }, "show tasks : show running tasks", NULL, cli_io_handler_show_tasks, NULL },
|
||||||
{{},}
|
{{},}
|
||||||
}};
|
}};
|
||||||
|
|
|
||||||
21
src/applet.c
21
src/applet.c
|
|
@ -31,7 +31,6 @@ unsigned int nb_applets = 0;
|
||||||
|
|
||||||
DECLARE_TYPED_POOL(pool_head_appctx, "appctx", struct appctx);
|
DECLARE_TYPED_POOL(pool_head_appctx, "appctx", struct appctx);
|
||||||
|
|
||||||
|
|
||||||
/* trace source and events */
|
/* trace source and events */
|
||||||
static void applet_trace(enum trace_level level, uint64_t mask,
|
static void applet_trace(enum trace_level level, uint64_t mask,
|
||||||
const struct trace_source *src,
|
const struct trace_source *src,
|
||||||
|
|
@ -417,7 +416,7 @@ void appctx_shut(struct appctx *appctx)
|
||||||
TRACE_ENTER(APPLET_EV_RELEASE, appctx);
|
TRACE_ENTER(APPLET_EV_RELEASE, appctx);
|
||||||
|
|
||||||
if (appctx->applet->release)
|
if (appctx->applet->release)
|
||||||
appctx->applet->release(appctx);
|
CALL_APPLET_NO_RET(appctx->applet, release(appctx));
|
||||||
applet_fl_set(appctx, APPCTX_FL_SHUTDOWN);
|
applet_fl_set(appctx, APPCTX_FL_SHUTDOWN);
|
||||||
|
|
||||||
b_dequeue(&appctx->buffer_wait);
|
b_dequeue(&appctx->buffer_wait);
|
||||||
|
|
@ -512,7 +511,7 @@ size_t appctx_htx_rcv_buf(struct appctx *appctx, struct buffer *buf, size_t coun
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
htx_xfer_blks(buf_htx, appctx_htx, count, HTX_BLK_UNUSED);
|
htx_xfer(buf_htx, appctx_htx, count, HTX_XFER_DEFAULT);
|
||||||
buf_htx->flags |= (appctx_htx->flags & (HTX_FL_PARSING_ERROR|HTX_FL_PROCESSING_ERROR));
|
buf_htx->flags |= (appctx_htx->flags & (HTX_FL_PARSING_ERROR|HTX_FL_PROCESSING_ERROR));
|
||||||
if (htx_is_empty(appctx_htx)) {
|
if (htx_is_empty(appctx_htx)) {
|
||||||
buf_htx->flags |= (appctx_htx->flags & HTX_FL_EOM);
|
buf_htx->flags |= (appctx_htx->flags & HTX_FL_EOM);
|
||||||
|
|
@ -551,7 +550,7 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
||||||
if (flags & CO_RFL_BUF_FLUSH)
|
if (flags & CO_RFL_BUF_FLUSH)
|
||||||
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
|
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
|
||||||
|
|
||||||
ret = appctx->applet->rcv_buf(appctx, buf, count, flags);
|
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
||||||
if (ret)
|
if (ret)
|
||||||
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
|
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
|
||||||
|
|
||||||
|
|
@ -609,7 +608,7 @@ size_t appctx_htx_snd_buf(struct appctx *appctx, struct buffer *buf, size_t coun
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
htx_xfer_blks(appctx_htx, buf_htx, count, HTX_BLK_UNUSED);
|
htx_xfer(appctx_htx, buf_htx, count, HTX_XFER_DEFAULT);
|
||||||
if (htx_is_empty(buf_htx)) {
|
if (htx_is_empty(buf_htx)) {
|
||||||
appctx_htx->flags |= (buf_htx->flags & HTX_FL_EOM);
|
appctx_htx->flags |= (buf_htx->flags & HTX_FL_EOM);
|
||||||
}
|
}
|
||||||
|
|
@ -659,7 +658,7 @@ size_t appctx_snd_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = appctx->applet->snd_buf(appctx, buf, count, flags);
|
ret = CALL_APPLET_WITH_RET(appctx->applet, snd_buf(appctx, buf, count, flags));
|
||||||
|
|
||||||
if (applet_fl_test(appctx, (APPCTX_FL_ERROR|APPCTX_FL_ERR_PENDING)))
|
if (applet_fl_test(appctx, (APPCTX_FL_ERROR|APPCTX_FL_ERR_PENDING)))
|
||||||
se_report_term_evt(appctx->sedesc, se_tevt_type_snd_err);
|
se_report_term_evt(appctx->sedesc, se_tevt_type_snd_err);
|
||||||
|
|
@ -716,7 +715,7 @@ int appctx_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
b_add(sdo->iobuf.buf, sdo->iobuf.offset);
|
b_add(sdo->iobuf.buf, sdo->iobuf.offset);
|
||||||
ret = appctx->applet->fastfwd(appctx, sdo->iobuf.buf, len, 0);
|
ret = CALL_APPLET_WITH_RET(appctx->applet, fastfwd(appctx, sdo->iobuf.buf, len, 0));
|
||||||
b_sub(sdo->iobuf.buf, sdo->iobuf.offset);
|
b_sub(sdo->iobuf.buf, sdo->iobuf.offset);
|
||||||
sdo->iobuf.data += ret;
|
sdo->iobuf.data += ret;
|
||||||
|
|
||||||
|
|
@ -853,7 +852,7 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state)
|
||||||
* already called)
|
* already called)
|
||||||
*/
|
*/
|
||||||
if (!se_fl_test(app->sedesc, SE_FL_SHR) || !se_fl_test(app->sedesc, SE_FL_SHW))
|
if (!se_fl_test(app->sedesc, SE_FL_SHR) || !se_fl_test(app->sedesc, SE_FL_SHW))
|
||||||
app->applet->fct(app);
|
CALL_APPLET_NO_RET(app->applet, fct(app));
|
||||||
|
|
||||||
TRACE_POINT(APPLET_EV_PROCESS, app);
|
TRACE_POINT(APPLET_EV_PROCESS, app);
|
||||||
|
|
||||||
|
|
@ -900,7 +899,7 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state)
|
||||||
stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate));
|
stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
sc->app_ops->wake(sc);
|
sc_applet_process(sc);
|
||||||
channel_release_buffer(ic, &app->buffer_wait);
|
channel_release_buffer(ic, &app->buffer_wait);
|
||||||
TRACE_LEAVE(APPLET_EV_PROCESS, app);
|
TRACE_LEAVE(APPLET_EV_PROCESS, app);
|
||||||
return t;
|
return t;
|
||||||
|
|
@ -954,7 +953,7 @@ struct task *task_process_applet(struct task *t, void *context, unsigned int sta
|
||||||
* already called)
|
* already called)
|
||||||
*/
|
*/
|
||||||
if (!applet_fl_test(app, APPCTX_FL_SHUTDOWN))
|
if (!applet_fl_test(app, APPCTX_FL_SHUTDOWN))
|
||||||
app->applet->fct(app);
|
CALL_APPLET_NO_RET(app->applet, fct(app));
|
||||||
|
|
||||||
TRACE_POINT(APPLET_EV_PROCESS, app);
|
TRACE_POINT(APPLET_EV_PROCESS, app);
|
||||||
|
|
||||||
|
|
@ -993,7 +992,7 @@ struct task *task_process_applet(struct task *t, void *context, unsigned int sta
|
||||||
stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate));
|
stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
sc->app_ops->wake(sc);
|
sc_applet_process(sc);
|
||||||
appctx_release_buffers(app);
|
appctx_release_buffers(app);
|
||||||
TRACE_LEAVE(APPLET_EV_PROCESS, app);
|
TRACE_LEAVE(APPLET_EV_PROCESS, app);
|
||||||
return t;
|
return t;
|
||||||
|
|
|
||||||
|
|
@ -1396,7 +1396,7 @@ check_tgid:
|
||||||
tree = search_tree ? &srv->per_thr[i].safe_conns : &srv->per_thr[i].idle_conns;
|
tree = search_tree ? &srv->per_thr[i].safe_conns : &srv->per_thr[i].idle_conns;
|
||||||
conn = srv_lookup_conn(tree, hash);
|
conn = srv_lookup_conn(tree, hash);
|
||||||
while (conn) {
|
while (conn) {
|
||||||
if (conn->mux->takeover && conn->mux->takeover(conn, i, 0) == 0) {
|
if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, i, 0)) == 0) {
|
||||||
conn_delete_from_tree(conn, i);
|
conn_delete_from_tree(conn, i);
|
||||||
_HA_ATOMIC_INC(&activity[tid].fd_takeover);
|
_HA_ATOMIC_INC(&activity[tid].fd_takeover);
|
||||||
found = 1;
|
found = 1;
|
||||||
|
|
@ -1498,7 +1498,7 @@ takeover_random_idle_conn(struct ceb_root **root, int curtid)
|
||||||
|
|
||||||
conn = ceb64_item_first(root, hash_node.node, hash_node.key, struct connection);
|
conn = ceb64_item_first(root, hash_node.node, hash_node.key, struct connection);
|
||||||
while (conn) {
|
while (conn) {
|
||||||
if (conn->mux->takeover && conn->mux->takeover(conn, curtid, 1) == 0) {
|
if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, curtid, 1)) == 0) {
|
||||||
conn_delete_from_tree(conn, curtid);
|
conn_delete_from_tree(conn, curtid);
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
@ -1555,7 +1555,7 @@ kill_random_idle_conn(struct server *srv)
|
||||||
*/
|
*/
|
||||||
_HA_ATOMIC_INC(&srv->curr_used_conns);
|
_HA_ATOMIC_INC(&srv->curr_used_conns);
|
||||||
}
|
}
|
||||||
conn->mux->destroy(conn->ctx);
|
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1765,7 +1765,7 @@ int be_reuse_connection(int64_t hash, struct session *sess,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avail >= 1) {
|
if (avail >= 1) {
|
||||||
if (srv_conn->mux->attach(srv_conn, sc->sedesc, sess) == -1) {
|
if (CALL_MUX_WITH_RET(srv_conn->mux, attach(srv_conn, sc->sedesc, sess)) == -1) {
|
||||||
if (sc_reset_endp(sc) < 0)
|
if (sc_reset_endp(sc) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
sc_ep_clr(sc, ~SE_FL_DETACHED);
|
sc_ep_clr(sc, ~SE_FL_DETACHED);
|
||||||
|
|
@ -1879,7 +1879,7 @@ int connect_server(struct stream *s)
|
||||||
* It will in turn call srv_release_conn through
|
* It will in turn call srv_release_conn through
|
||||||
* conn_free which also uses it.
|
* conn_free which also uses it.
|
||||||
*/
|
*/
|
||||||
tokill_conn->mux->destroy(tokill_conn->ctx);
|
CALL_MUX_NO_RET(tokill_conn->mux, destroy(tokill_conn->ctx));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
|
||||||
|
|
@ -2204,7 +2204,7 @@ int connect_server(struct stream *s)
|
||||||
*/
|
*/
|
||||||
if (may_start_mux_now) {
|
if (may_start_mux_now) {
|
||||||
const struct mux_ops *alt_mux =
|
const struct mux_ops *alt_mux =
|
||||||
likely(!(s->flags & SF_WEBSOCKET)) ? NULL : srv_get_ws_proto(srv);
|
likely(!(s->flags & SF_WEBSOCKET) || !srv) ? NULL : srv_get_ws_proto(srv);
|
||||||
if (conn_install_mux_be(srv_conn, s->scb, s->sess, alt_mux) < 0) {
|
if (conn_install_mux_be(srv_conn, s->scb, s->sess, alt_mux) < 0) {
|
||||||
conn_full_close(srv_conn);
|
conn_full_close(srv_conn);
|
||||||
return SF_ERR_INTERNAL;
|
return SF_ERR_INTERNAL;
|
||||||
|
|
@ -2266,7 +2266,7 @@ int connect_server(struct stream *s)
|
||||||
|
|
||||||
s->flags |= SF_CURR_SESS;
|
s->flags |= SF_CURR_SESS;
|
||||||
count = _HA_ATOMIC_ADD_FETCH(&srv->cur_sess, 1);
|
count = _HA_ATOMIC_ADD_FETCH(&srv->cur_sess, 1);
|
||||||
HA_ATOMIC_UPDATE_MAX(&srv->counters.cur_sess_max, count);
|
COUNTERS_UPDATE_MAX(&srv->counters.cur_sess_max, count);
|
||||||
if (s->be->lbprm.server_take_conn)
|
if (s->be->lbprm.server_take_conn)
|
||||||
s->be->lbprm.server_take_conn(srv);
|
s->be->lbprm.server_take_conn(srv);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -626,7 +626,7 @@ cache_store_check(struct proxy *px, struct flt_conf *fconf)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (f->id == http_comp_flt_id)
|
else if (f->id == http_comp_req_flt_id || f->id == http_comp_res_flt_id)
|
||||||
comp = 1;
|
comp = 1;
|
||||||
else if (f->id == fcgi_flt_id)
|
else if (f->id == fcgi_flt_id)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,23 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
|
||||||
global.tune.options |= GTUNE_BUSY_POLLING;
|
global.tune.options |= GTUNE_BUSY_POLLING;
|
||||||
}
|
}
|
||||||
else if (strcmp(args[0], "set-dumpable") == 0) { /* "no set-dumpable" or "set-dumpable" */
|
else if (strcmp(args[0], "set-dumpable") == 0) { /* "no set-dumpable" or "set-dumpable" */
|
||||||
if (alertif_too_many_args(0, file, linenum, args, &err_code))
|
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||||
goto out;
|
goto out;
|
||||||
if (kwm == KWM_NO)
|
if (kwm == KWM_NO) {
|
||||||
global.tune.options &= ~GTUNE_SET_DUMPABLE;
|
global.tune.options &= ~GTUNE_SET_DUMPABLE;
|
||||||
else
|
goto out;
|
||||||
|
}
|
||||||
|
if (!*args[1] || strcmp(args[1], "on") == 0)
|
||||||
global.tune.options |= GTUNE_SET_DUMPABLE;
|
global.tune.options |= GTUNE_SET_DUMPABLE;
|
||||||
|
else if (strcmp(args[1], "libs") == 0)
|
||||||
|
global.tune.options |= GTUNE_SET_DUMPABLE | GTUNE_COLLECT_LIBS;
|
||||||
|
else if (strcmp(args[1], "off") == 0)
|
||||||
|
global.tune.options &= ~GTUNE_SET_DUMPABLE;
|
||||||
|
else {
|
||||||
|
ha_alert("parsing [%s:%d] : '%s' only supports 'on' and 'off' as an argument, found '%s'.\n", file, linenum, args[0], args[1]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(args[0], "h2-workaround-bogus-websocket-clients") == 0) { /* "no h2-workaround-bogus-websocket-clients" or "h2-workaround-bogus-websocket-clients" */
|
else if (strcmp(args[0], "h2-workaround-bogus-websocket-clients") == 0) { /* "no h2-workaround-bogus-websocket-clients" or "h2-workaround-bogus-websocket-clients" */
|
||||||
if (alertif_too_many_args(0, file, linenum, args, &err_code))
|
if (alertif_too_many_args(0, file, linenum, args, &err_code))
|
||||||
|
|
@ -456,9 +467,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
|
||||||
for (i = 1; *args[i]; i++)
|
for (i = 1; *args[i]; i++)
|
||||||
len += strlen(args[i]) + 1;
|
len += strlen(args[i]) + 1;
|
||||||
|
|
||||||
if (global.desc)
|
|
||||||
free(global.desc);
|
free(global.desc);
|
||||||
|
|
||||||
global.desc = d = calloc(1, len);
|
global.desc = d = calloc(1, len);
|
||||||
|
|
||||||
d += snprintf(d, global.desc + len - d, "%s", args[1]);
|
d += snprintf(d, global.desc + len - d, "%s", args[1]);
|
||||||
|
|
@ -487,9 +496,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.node)
|
|
||||||
free(global.node);
|
free(global.node);
|
||||||
|
|
||||||
global.node = strdup(args[1]);
|
global.node = strdup(args[1]);
|
||||||
}
|
}
|
||||||
else if (strcmp(args[0], "unix-bind") == 0) {
|
else if (strcmp(args[0], "unix-bind") == 0) {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include <haproxy/proxy.h>
|
#include <haproxy/proxy.h>
|
||||||
#include <haproxy/sample.h>
|
#include <haproxy/sample.h>
|
||||||
#include <haproxy/server.h>
|
#include <haproxy/server.h>
|
||||||
#include <haproxy/stats-t.h>
|
|
||||||
#include <haproxy/stick_table.h>
|
#include <haproxy/stick_table.h>
|
||||||
#include <haproxy/tcpcheck.h>
|
#include <haproxy/tcpcheck.h>
|
||||||
#include <haproxy/tools.h>
|
#include <haproxy/tools.h>
|
||||||
|
|
@ -394,7 +393,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
* freed unless it is still referenced by proxies.
|
* freed unless it is still referenced by proxies.
|
||||||
*/
|
*/
|
||||||
if (last_defproxy && last_defproxy->id[0] == '\0' &&
|
if (last_defproxy && last_defproxy->id[0] == '\0' &&
|
||||||
!last_defproxy->conf.refcount) {
|
!last_defproxy->conf.def_ref) {
|
||||||
defaults_px_destroy(last_defproxy);
|
defaults_px_destroy(last_defproxy);
|
||||||
}
|
}
|
||||||
last_defproxy = NULL;
|
last_defproxy = NULL;
|
||||||
|
|
@ -669,6 +668,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* valid mode, non "haterm" mode.
|
||||||
|
* Possibly restore the ->stream_new_from_sc() callback
|
||||||
|
* if set by default for "haterm" mode.
|
||||||
|
*/
|
||||||
|
curproxy->stream_new_from_sc = stream_new;
|
||||||
|
}
|
||||||
|
|
||||||
curproxy->mode = mode;
|
curproxy->mode = mode;
|
||||||
if (curproxy->cap & PR_CAP_DEF)
|
if (curproxy->cap & PR_CAP_DEF)
|
||||||
|
|
@ -1352,14 +1358,15 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_code |= warnif_misplaced_http_req(curproxy, file, linenum, args[0], NULL);
|
if (warnif_misplaced_http_req(curproxy, file, linenum, args[0], NULL))
|
||||||
|
err_code |= ERR_WARN;
|
||||||
|
|
||||||
if (curproxy->cap & PR_CAP_FE)
|
if (curproxy->cap & PR_CAP_FE)
|
||||||
where |= SMP_VAL_FE_HRQ_HDR;
|
where |= SMP_VAL_FE_HRQ_HDR;
|
||||||
if (curproxy->cap & PR_CAP_BE)
|
if (curproxy->cap & PR_CAP_BE)
|
||||||
where |= SMP_VAL_BE_HRQ_HDR;
|
where |= SMP_VAL_BE_HRQ_HDR;
|
||||||
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
|
|
||||||
LIST_APPEND(&curproxy->http_req_rules, &rule->list);
|
LIST_APPEND(&curproxy->http_req_rules, &rule->list);
|
||||||
|
|
@ -1394,7 +1401,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
if (curproxy->cap & PR_CAP_BE)
|
if (curproxy->cap & PR_CAP_BE)
|
||||||
where |= SMP_VAL_BE_HRS_HDR;
|
where |= SMP_VAL_BE_HRS_HDR;
|
||||||
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
|
|
||||||
LIST_APPEND(&curproxy->http_res_rules, &rule->list);
|
LIST_APPEND(&curproxy->http_res_rules, &rule->list);
|
||||||
|
|
@ -1428,7 +1435,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
if (curproxy->cap & PR_CAP_BE)
|
if (curproxy->cap & PR_CAP_BE)
|
||||||
where |= SMP_VAL_BE_HRS_HDR;
|
where |= SMP_VAL_BE_HRS_HDR;
|
||||||
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
|
|
||||||
LIST_APPEND(&curproxy->http_after_res_rules, &rule->list);
|
LIST_APPEND(&curproxy->http_after_res_rules, &rule->list);
|
||||||
|
|
@ -1485,14 +1492,15 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_APPEND(&curproxy->redirect_rules, &rule->list);
|
LIST_APPEND(&curproxy->redirect_rules, &rule->list);
|
||||||
err_code |= warnif_misplaced_redirect(curproxy, file, linenum, args[0], NULL);
|
if (warnif_misplaced_redirect(curproxy, file, linenum, args[0], NULL))
|
||||||
|
err_code |= ERR_WARN;
|
||||||
|
|
||||||
if (curproxy->cap & PR_CAP_FE)
|
if (curproxy->cap & PR_CAP_FE)
|
||||||
where |= SMP_VAL_FE_HRQ_HDR;
|
where |= SMP_VAL_FE_HRQ_HDR;
|
||||||
if (curproxy->cap & PR_CAP_BE)
|
if (curproxy->cap & PR_CAP_BE)
|
||||||
where |= SMP_VAL_BE_HRQ_HDR;
|
where |= SMP_VAL_BE_HRQ_HDR;
|
||||||
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
}
|
}
|
||||||
else if (strcmp(args[0], "use_backend") == 0) {
|
else if (strcmp(args[0], "use_backend") == 0) {
|
||||||
|
|
@ -1522,7 +1530,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
}
|
}
|
||||||
|
|
||||||
err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, &errmsg);
|
err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
}
|
}
|
||||||
else if (*args[2]) {
|
else if (*args[2]) {
|
||||||
|
|
@ -1585,7 +1593,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
}
|
}
|
||||||
|
|
||||||
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, &errmsg);
|
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
|
|
||||||
rule = calloc(1, sizeof(*rule));
|
rule = calloc(1, sizeof(*rule));
|
||||||
|
|
@ -1640,7 +1648,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
* where force-persist is applied.
|
* where force-persist is applied.
|
||||||
*/
|
*/
|
||||||
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, &errmsg);
|
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
|
|
||||||
rule = calloc(1, sizeof(*rule));
|
rule = calloc(1, sizeof(*rule));
|
||||||
|
|
@ -1808,7 +1816,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, &errmsg);
|
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, &errmsg);
|
||||||
else
|
else
|
||||||
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, &errmsg);
|
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
|
|
||||||
rule = calloc(1, sizeof(*rule));
|
rule = calloc(1, sizeof(*rule));
|
||||||
|
|
@ -1866,7 +1874,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
if (curproxy->cap & PR_CAP_BE)
|
if (curproxy->cap & PR_CAP_BE)
|
||||||
where |= SMP_VAL_BE_HRQ_HDR;
|
where |= SMP_VAL_BE_HRQ_HDR;
|
||||||
err_code |= warnif_cond_conflicts(cond, where, &errmsg);
|
err_code |= warnif_cond_conflicts(cond, where, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
|
|
||||||
rule = calloc(1, sizeof(*rule));
|
rule = calloc(1, sizeof(*rule));
|
||||||
|
|
@ -1946,7 +1954,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||||
if (curproxy->cap & PR_CAP_BE)
|
if (curproxy->cap & PR_CAP_BE)
|
||||||
where |= SMP_VAL_BE_HRQ_HDR;
|
where |= SMP_VAL_BE_HRQ_HDR;
|
||||||
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
|
||||||
if (err_code)
|
if (errmsg && *errmsg)
|
||||||
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
|
||||||
LIST_APPEND(&curproxy->uri_auth->http_req_rules, &rule->list);
|
LIST_APPEND(&curproxy->uri_auth->http_req_rules, &rule->list);
|
||||||
|
|
||||||
|
|
@ -2194,6 +2202,42 @@ stats_error_parsing:
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(args[1], "use-small-buffers") == 0) {
|
||||||
|
unsigned int flags = PR_O2_USE_SBUF_ALL;
|
||||||
|
|
||||||
|
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
|
||||||
|
err_code |= ERR_WARN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(args[2])) {
|
||||||
|
int cur_arg;
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
for (cur_arg = 2; *(args[cur_arg]); cur_arg++) {
|
||||||
|
if (strcmp(args[cur_arg], "queue") == 0)
|
||||||
|
flags |= PR_O2_USE_SBUF_QUEUE;
|
||||||
|
else if (strcmp(args[cur_arg], "l7-retries") == 0)
|
||||||
|
flags |= PR_O2_USE_SBUF_L7_RETRY;
|
||||||
|
else if (strcmp(args[cur_arg], "check") == 0)
|
||||||
|
flags |= PR_O2_USE_SBUF_CHECK;
|
||||||
|
else {
|
||||||
|
ha_alert("parsing [%s:%d] : invalid parameter '%s'. option '%s' expects 'queue', 'l7-retries' or 'check' value.\n",
|
||||||
|
file, linenum, args[cur_arg], args[1]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kwm == KWM_STD) {
|
||||||
|
curproxy->options2 &= ~PR_O2_USE_SBUF_ALL;
|
||||||
|
curproxy->options2 |= flags;
|
||||||
|
}
|
||||||
|
else if (kwm == KWM_NO) {
|
||||||
|
curproxy->options2 &= ~flags;
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (kwm != KWM_STD) {
|
if (kwm != KWM_STD) {
|
||||||
ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
|
ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
|
||||||
|
|
@ -2454,18 +2498,7 @@ stats_error_parsing:
|
||||||
}
|
}
|
||||||
|
|
||||||
curproxy->no_options2 &= ~val;
|
curproxy->no_options2 &= ~val;
|
||||||
curproxy->options2 &= ~val;
|
|
||||||
|
|
||||||
switch (kwm) {
|
|
||||||
case KWM_STD:
|
|
||||||
curproxy->options2 |= val;
|
curproxy->options2 |= val;
|
||||||
break;
|
|
||||||
case KWM_NO:
|
|
||||||
curproxy->no_options2 |= val;
|
|
||||||
break;
|
|
||||||
case KWM_DEF: /* already cleared */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
err_code |= ERR_WARN;
|
err_code |= ERR_WARN;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -2562,7 +2595,8 @@ stats_error_parsing:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_code |= warnif_misplaced_monitor(curproxy, file, linenum, args[0], args[1]);
|
if (warnif_misplaced_monitor(curproxy, file, linenum, args[0], args[1]))
|
||||||
|
err_code |= ERR_WARN;
|
||||||
if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
|
if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
|
||||||
ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
|
ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
|
||||||
file, linenum, args[0], args[1], errmsg);
|
file, linenum, args[0], args[1], errmsg);
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,6 @@ static int ssl_parse_global_ssl_async(char **args, int section_type, struct prox
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
|
|
||||||
/* parse the "ssl-engine" keyword in global section.
|
/* parse the "ssl-engine" keyword in global section.
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
*/
|
*/
|
||||||
|
|
@ -151,6 +150,7 @@ static int ssl_parse_global_ssl_engine(char **args, int section_type, struct pro
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
|
||||||
char *algo;
|
char *algo;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
|
|
@ -184,10 +184,12 @@ add_engine:
|
||||||
}
|
}
|
||||||
free(algo);
|
free(algo);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
#else
|
||||||
|
memprintf(err, "'%s' is not supported (built without USE_ENGINE or with -DOPENSSL_NO_ENGINE).", args[0]);
|
||||||
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SSL_PROVIDERS
|
|
||||||
/* parse the "ssl-propquery" keyword in global section.
|
/* parse the "ssl-propquery" keyword in global section.
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
*/
|
*/
|
||||||
|
|
@ -195,6 +197,7 @@ static int ssl_parse_global_ssl_propquery(char **args, int section_type, struct
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_SSL_PROVIDERS
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (*(args[1]) == 0) {
|
if (*(args[1]) == 0) {
|
||||||
|
|
@ -206,6 +209,10 @@ static int ssl_parse_global_ssl_propquery(char **args, int section_type, struct
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
#else
|
||||||
|
memprintf(err, "'%s' is not supported by %s.", args[0], OpenSSL_version(OPENSSL_VERSION));
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse the "ssl-provider" keyword in global section.
|
/* parse the "ssl-provider" keyword in global section.
|
||||||
|
|
@ -215,6 +222,7 @@ static int ssl_parse_global_ssl_provider(char **args, int section_type, struct p
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_SSL_PROVIDERS
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (*(args[1]) == 0) {
|
if (*(args[1]) == 0) {
|
||||||
|
|
@ -226,6 +234,10 @@ static int ssl_parse_global_ssl_provider(char **args, int section_type, struct p
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
#else
|
||||||
|
memprintf(err, "'%s' is not supported by %s.", args[0], OpenSSL_version(OPENSSL_VERSION));
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse the "ssl-provider-path" keyword in global section.
|
/* parse the "ssl-provider-path" keyword in global section.
|
||||||
|
|
@ -235,6 +247,7 @@ static int ssl_parse_global_ssl_provider_path(char **args, int section_type, str
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_SSL_PROVIDERS
|
||||||
if (*(args[1]) == 0) {
|
if (*(args[1]) == 0) {
|
||||||
memprintf(err, "global statement '%s' expects a directory path as an argument.", args[0]);
|
memprintf(err, "global statement '%s' expects a directory path as an argument.", args[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -243,8 +256,11 @@ static int ssl_parse_global_ssl_provider_path(char **args, int section_type, str
|
||||||
OSSL_PROVIDER_set_default_search_path(NULL, args[1]);
|
OSSL_PROVIDER_set_default_search_path(NULL, args[1]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
#else
|
||||||
|
memprintf(err, "'%s' is not supported by %s.", args[0], OpenSSL_version(OPENSSL_VERSION));
|
||||||
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* parse the "ssl-default-bind-ciphers" / "ssl-default-server-ciphers" keywords
|
/* parse the "ssl-default-bind-ciphers" / "ssl-default-server-ciphers" keywords
|
||||||
* in global section. Returns <0 on alert, >0 on warning, 0 on success.
|
* in global section. Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
|
|
@ -300,7 +316,6 @@ static int ssl_parse_global_ciphersuites(char **args, int section_type, struct p
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SSL_CTX_set1_curves_list)
|
|
||||||
/*
|
/*
|
||||||
* parse the "ssl-default-bind-curves" keyword in a global section.
|
* parse the "ssl-default-bind-curves" keyword in a global section.
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
|
|
@ -309,6 +324,10 @@ static int ssl_parse_global_curves(char **args, int section_type, struct proxy *
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#ifndef SSL_CTX_set1_curves_list
|
||||||
|
memprintf(err, "'%s' is not supported by %s.", args[0], OpenSSL_version(OPENSSL_VERSION));
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
char **target;
|
char **target;
|
||||||
target = (args[0][12] == 'b') ? &global_ssl.listen_default_curves : &global_ssl.connect_default_curves;
|
target = (args[0][12] == 'b') ? &global_ssl.listen_default_curves : &global_ssl.connect_default_curves;
|
||||||
|
|
||||||
|
|
@ -323,10 +342,9 @@ static int ssl_parse_global_curves(char **args, int section_type, struct proxy *
|
||||||
free(*target);
|
free(*target);
|
||||||
*target = strdup(args[1]);
|
*target = strdup(args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(SSL_CTX_set1_sigalgs_list)
|
|
||||||
/*
|
/*
|
||||||
* parse the "ssl-default-bind-sigalgs" and "ssl-default-server-sigalgs" keyword in a global section.
|
* parse the "ssl-default-bind-sigalgs" and "ssl-default-server-sigalgs" keyword in a global section.
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
|
|
@ -335,6 +353,10 @@ static int ssl_parse_global_sigalgs(char **args, int section_type, struct proxy
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#ifndef SSL_CTX_set1_sigalgs_list
|
||||||
|
memprintf(err, "'%s' is not supported by %s.", args[0], OpenSSL_version(OPENSSL_VERSION));
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
char **target;
|
char **target;
|
||||||
|
|
||||||
target = (args[0][12] == 'b') ? &global_ssl.listen_default_sigalgs : &global_ssl.connect_default_sigalgs;
|
target = (args[0][12] == 'b') ? &global_ssl.listen_default_sigalgs : &global_ssl.connect_default_sigalgs;
|
||||||
|
|
@ -350,10 +372,9 @@ static int ssl_parse_global_sigalgs(char **args, int section_type, struct proxy
|
||||||
free(*target);
|
free(*target);
|
||||||
*target = strdup(args[1]);
|
*target = strdup(args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(SSL_CTX_set1_client_sigalgs_list)
|
|
||||||
/*
|
/*
|
||||||
* parse the "ssl-default-bind-client-sigalgs" keyword in a global section.
|
* parse the "ssl-default-bind-client-sigalgs" keyword in a global section.
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
|
|
@ -362,6 +383,10 @@ static int ssl_parse_global_client_sigalgs(char **args, int section_type, struct
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#ifndef SSL_CTX_set1_client_sigalgs_list
|
||||||
|
memprintf(err, "'%s' is not supported by %s.", args[0], OpenSSL_version(OPENSSL_VERSION));
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
char **target;
|
char **target;
|
||||||
|
|
||||||
target = (args[0][12] == 'b') ? &global_ssl.listen_default_client_sigalgs : &global_ssl.connect_default_client_sigalgs;
|
target = (args[0][12] == 'b') ? &global_ssl.listen_default_client_sigalgs : &global_ssl.connect_default_client_sigalgs;
|
||||||
|
|
@ -377,8 +402,8 @@ static int ssl_parse_global_client_sigalgs(char **args, int section_type, struct
|
||||||
free(*target);
|
free(*target);
|
||||||
*target = strdup(args[1]);
|
*target = strdup(args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* parse various global tune.ssl settings consisting in positive integers.
|
/* parse various global tune.ssl settings consisting in positive integers.
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
|
|
@ -575,7 +600,6 @@ static int ssl_parse_global_lifetime(char **args, int section_type, struct proxy
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_DH
|
|
||||||
/* parse "ssl-dh-param-file".
|
/* parse "ssl-dh-param-file".
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
*/
|
*/
|
||||||
|
|
@ -583,6 +607,7 @@ static int ssl_parse_global_dh_param_file(char **args, int section_type, struct
|
||||||
const struct proxy *defpx, const char *file, int line,
|
const struct proxy *defpx, const char *file, int line,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
|
#ifndef OPENSSL_NO_DH
|
||||||
if (too_many_args(1, args, err, NULL))
|
if (too_many_args(1, args, err, NULL))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
@ -596,9 +621,11 @@ static int ssl_parse_global_dh_param_file(char **args, int section_type, struct
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
#else
|
||||||
|
memprintf(err, "'%s' is not supported by %s (no DH support).", args[0], OpenSSL_version(OPENSSL_VERSION));
|
||||||
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* parse "ssl.default-dh-param".
|
/* parse "ssl.default-dh-param".
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
|
|
@ -2738,12 +2765,12 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
|
||||||
{ "force-tlsv12", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv12 */
|
{ "force-tlsv12", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv12 */
|
||||||
{ "force-tlsv13", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv13 */
|
{ "force-tlsv13", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv13 */
|
||||||
{ "ktls", srv_parse_ktls, 1, 1, 1 }, /* enable or disable kTLS */
|
{ "ktls", srv_parse_ktls, 1, 1, 1 }, /* enable or disable kTLS */
|
||||||
{ "no-check-sni-auto", srv_parse_no_check_sni_auto, 0, 1, 0 }, /* disable automatic SNI selection for health checks */
|
{ "no-check-sni-auto", srv_parse_no_check_sni_auto, 0, 1, 1 }, /* disable automatic SNI selection for health checks */
|
||||||
{ "no-check-ssl", srv_parse_no_check_ssl, 0, 1, 0 }, /* disable SSL for health checks */
|
{ "no-check-ssl", srv_parse_no_check_ssl, 0, 1, 0 }, /* disable SSL for health checks */
|
||||||
{ "no-renegotiate", srv_parse_renegotiate, 0, 1, 1 }, /* Disable renegotiation */
|
{ "no-renegotiate", srv_parse_renegotiate, 0, 1, 1 }, /* Disable renegotiation */
|
||||||
{ "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1, 0 }, /* do not send PROXY protocol header v2 with SSL info */
|
{ "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1, 0 }, /* do not send PROXY protocol header v2 with SSL info */
|
||||||
{ "no-send-proxy-v2-ssl-cn", srv_parse_no_send_proxy_cn, 0, 1, 0 }, /* do not send PROXY protocol header v2 with CN */
|
{ "no-send-proxy-v2-ssl-cn", srv_parse_no_send_proxy_cn, 0, 1, 0 }, /* do not send PROXY protocol header v2 with CN */
|
||||||
{ "no-sni-auto", srv_parse_no_sni_auto, 0, 1, 0 }, /* disable automatic SNI selection */
|
{ "no-sni-auto", srv_parse_no_sni_auto, 0, 1, 1 }, /* disable automatic SNI selection */
|
||||||
{ "no-ssl", srv_parse_no_ssl, 0, 1, 0 }, /* disable SSL processing */
|
{ "no-ssl", srv_parse_no_ssl, 0, 1, 0 }, /* disable SSL processing */
|
||||||
{ "no-ssl-reuse", srv_parse_no_ssl_reuse, 0, 1, 1 }, /* disable session reuse */
|
{ "no-ssl-reuse", srv_parse_no_ssl_reuse, 0, 1, 1 }, /* disable session reuse */
|
||||||
{ "no-sslv3", srv_parse_tls_method_options, 0, 0, 1 }, /* disable SSLv3 */
|
{ "no-sslv3", srv_parse_tls_method_options, 0, 0, 1 }, /* disable SSLv3 */
|
||||||
|
|
@ -2779,18 +2806,12 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
||||||
{ CFG_GLOBAL, "maxsslconn", ssl_parse_global_int },
|
{ CFG_GLOBAL, "maxsslconn", ssl_parse_global_int },
|
||||||
{ CFG_GLOBAL, "ssl-default-bind-options", ssl_parse_default_bind_options },
|
{ CFG_GLOBAL, "ssl-default-bind-options", ssl_parse_default_bind_options },
|
||||||
{ CFG_GLOBAL, "ssl-default-server-options", ssl_parse_default_server_options },
|
{ CFG_GLOBAL, "ssl-default-server-options", ssl_parse_default_server_options },
|
||||||
#ifndef OPENSSL_NO_DH
|
|
||||||
{ CFG_GLOBAL, "ssl-dh-param-file", ssl_parse_global_dh_param_file },
|
{ CFG_GLOBAL, "ssl-dh-param-file", ssl_parse_global_dh_param_file },
|
||||||
#endif
|
|
||||||
{ CFG_GLOBAL, "ssl-mode-async", ssl_parse_global_ssl_async },
|
{ CFG_GLOBAL, "ssl-mode-async", ssl_parse_global_ssl_async },
|
||||||
#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
|
|
||||||
{ CFG_GLOBAL, "ssl-engine", ssl_parse_global_ssl_engine },
|
{ CFG_GLOBAL, "ssl-engine", ssl_parse_global_ssl_engine },
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SSL_PROVIDERS
|
|
||||||
{ CFG_GLOBAL, "ssl-propquery", ssl_parse_global_ssl_propquery },
|
{ CFG_GLOBAL, "ssl-propquery", ssl_parse_global_ssl_propquery },
|
||||||
{ CFG_GLOBAL, "ssl-provider", ssl_parse_global_ssl_provider },
|
{ CFG_GLOBAL, "ssl-provider", ssl_parse_global_ssl_provider },
|
||||||
{ CFG_GLOBAL, "ssl-provider-path", ssl_parse_global_ssl_provider_path },
|
{ CFG_GLOBAL, "ssl-provider-path", ssl_parse_global_ssl_provider_path },
|
||||||
#endif
|
|
||||||
{ CFG_GLOBAL, "ssl-security-level", ssl_parse_security_level },
|
{ CFG_GLOBAL, "ssl-security-level", ssl_parse_security_level },
|
||||||
{ CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
|
{ CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
|
||||||
{ CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
|
{ CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
|
||||||
|
|
@ -2806,18 +2827,12 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
||||||
{ CFG_GLOBAL, "tune.ssl.keylog", ssl_parse_global_keylog },
|
{ CFG_GLOBAL, "tune.ssl.keylog", ssl_parse_global_keylog },
|
||||||
{ CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
|
{ CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
|
||||||
{ CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
|
{ CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
|
||||||
#if defined(SSL_CTX_set1_curves_list)
|
|
||||||
{ CFG_GLOBAL, "ssl-default-bind-curves", ssl_parse_global_curves },
|
{ CFG_GLOBAL, "ssl-default-bind-curves", ssl_parse_global_curves },
|
||||||
{ CFG_GLOBAL, "ssl-default-server-curves", ssl_parse_global_curves },
|
{ CFG_GLOBAL, "ssl-default-server-curves", ssl_parse_global_curves },
|
||||||
#endif
|
|
||||||
#if defined(SSL_CTX_set1_sigalgs_list)
|
|
||||||
{ CFG_GLOBAL, "ssl-default-bind-sigalgs", ssl_parse_global_sigalgs },
|
{ CFG_GLOBAL, "ssl-default-bind-sigalgs", ssl_parse_global_sigalgs },
|
||||||
{ CFG_GLOBAL, "ssl-default-server-sigalgs", ssl_parse_global_sigalgs },
|
{ CFG_GLOBAL, "ssl-default-server-sigalgs", ssl_parse_global_sigalgs },
|
||||||
#endif
|
|
||||||
#if defined(SSL_CTX_set1_client_sigalgs_list)
|
|
||||||
{ CFG_GLOBAL, "ssl-default-bind-client-sigalgs", ssl_parse_global_client_sigalgs },
|
{ CFG_GLOBAL, "ssl-default-bind-client-sigalgs", ssl_parse_global_client_sigalgs },
|
||||||
{ CFG_GLOBAL, "ssl-default-server-client-sigalgs", ssl_parse_global_client_sigalgs },
|
{ CFG_GLOBAL, "ssl-default-server-client-sigalgs", ssl_parse_global_client_sigalgs },
|
||||||
#endif
|
|
||||||
{ CFG_GLOBAL, "ssl-default-bind-ciphersuites", ssl_parse_global_ciphersuites },
|
{ CFG_GLOBAL, "ssl-default-bind-ciphersuites", ssl_parse_global_ciphersuites },
|
||||||
{ CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
|
{ CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
|
||||||
{ CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
|
{ CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@
|
||||||
#include <haproxy/global.h>
|
#include <haproxy/global.h>
|
||||||
#include <haproxy/http_ana.h>
|
#include <haproxy/http_ana.h>
|
||||||
#include <haproxy/http_rules.h>
|
#include <haproxy/http_rules.h>
|
||||||
|
#include <haproxy/http_htx.h>
|
||||||
#include <haproxy/lb_chash.h>
|
#include <haproxy/lb_chash.h>
|
||||||
#include <haproxy/lb_fas.h>
|
#include <haproxy/lb_fas.h>
|
||||||
#include <haproxy/lb_fwlc.h>
|
#include <haproxy/lb_fwlc.h>
|
||||||
|
|
@ -88,7 +89,6 @@
|
||||||
#include <haproxy/sample.h>
|
#include <haproxy/sample.h>
|
||||||
#include <haproxy/server.h>
|
#include <haproxy/server.h>
|
||||||
#include <haproxy/session.h>
|
#include <haproxy/session.h>
|
||||||
#include <haproxy/stats-t.h>
|
|
||||||
#include <haproxy/stick_table.h>
|
#include <haproxy/stick_table.h>
|
||||||
#include <haproxy/stream.h>
|
#include <haproxy/stream.h>
|
||||||
#include <haproxy/task.h>
|
#include <haproxy/task.h>
|
||||||
|
|
@ -2319,6 +2319,18 @@ int check_config_validity()
|
||||||
"Please fix either value to remove this warning.\n",
|
"Please fix either value to remove this warning.\n",
|
||||||
global.tune.bufsize_large, global.tune.bufsize);
|
global.tune.bufsize_large, global.tune.bufsize);
|
||||||
global.tune.bufsize_large = 0;
|
global.tune.bufsize_large = 0;
|
||||||
|
err_code |= ERR_WARN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global.tune.bufsize_small > 0) {
|
||||||
|
if (global.tune.bufsize_small == global.tune.bufsize)
|
||||||
|
global.tune.bufsize_small = 0;
|
||||||
|
else if (global.tune.bufsize_small > global.tune.bufsize) {
|
||||||
|
ha_warning("invalid small buffer size %d bytes which is greater to default bufsize %d bytes.\n",
|
||||||
|
global.tune.bufsize_small, global.tune.bufsize);
|
||||||
|
global.tune.bufsize_small = 0;
|
||||||
|
err_code |= ERR_WARN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2378,6 +2390,9 @@ int check_config_validity()
|
||||||
cfgerr += check_action_rules(&defpx->http_req_rules, defpx, &err_code);
|
cfgerr += check_action_rules(&defpx->http_req_rules, defpx, &err_code);
|
||||||
cfgerr += check_action_rules(&defpx->http_res_rules, defpx, &err_code);
|
cfgerr += check_action_rules(&defpx->http_res_rules, defpx, &err_code);
|
||||||
cfgerr += check_action_rules(&defpx->http_after_res_rules, defpx, &err_code);
|
cfgerr += check_action_rules(&defpx->http_after_res_rules, defpx, &err_code);
|
||||||
|
#ifdef USE_QUIC
|
||||||
|
cfgerr += check_action_rules(&defpx->quic_init_rules, defpx, &err_code);
|
||||||
|
#endif
|
||||||
|
|
||||||
err = NULL;
|
err = NULL;
|
||||||
i = smp_resolve_args(defpx, &err);
|
i = smp_resolve_args(defpx, &err);
|
||||||
|
|
@ -2390,6 +2405,8 @@ int check_config_validity()
|
||||||
else {
|
else {
|
||||||
cfgerr += acl_find_targets(defpx);
|
cfgerr += acl_find_targets(defpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err_code |= proxy_check_http_errors(defpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* starting to initialize the main proxies list */
|
/* starting to initialize the main proxies list */
|
||||||
|
|
|
||||||
53
src/check.c
53
src/check.c
|
|
@ -34,7 +34,7 @@
|
||||||
#include <haproxy/cfgparse.h>
|
#include <haproxy/cfgparse.h>
|
||||||
#include <haproxy/check.h>
|
#include <haproxy/check.h>
|
||||||
#include <haproxy/chunk.h>
|
#include <haproxy/chunk.h>
|
||||||
#include <haproxy/counters.h>
|
#include <haproxy/counters-t.h>
|
||||||
#include <haproxy/dgram.h>
|
#include <haproxy/dgram.h>
|
||||||
#include <haproxy/dynbuf.h>
|
#include <haproxy/dynbuf.h>
|
||||||
#include <haproxy/extcheck.h>
|
#include <haproxy/extcheck.h>
|
||||||
|
|
@ -58,7 +58,6 @@
|
||||||
#include <haproxy/sample.h>
|
#include <haproxy/sample.h>
|
||||||
#include <haproxy/server.h>
|
#include <haproxy/server.h>
|
||||||
#include <haproxy/ssl_sock.h>
|
#include <haproxy/ssl_sock.h>
|
||||||
#include <haproxy/stats-t.h>
|
|
||||||
#include <haproxy/task.h>
|
#include <haproxy/task.h>
|
||||||
#include <haproxy/tcpcheck.h>
|
#include <haproxy/tcpcheck.h>
|
||||||
#include <haproxy/thread.h>
|
#include <haproxy/thread.h>
|
||||||
|
|
@ -1046,13 +1045,12 @@ int httpchk_build_status_header(struct server *s, struct buffer *buf)
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/***************** Health-checks based on connections *********************/
|
/***************** Health-checks based on connections *********************/
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* This function is used only for server health-checks. It handles connection
|
/* This function handles connection status updates including errors. If
|
||||||
* status updates including errors. If necessary, it wakes the check task up.
|
* necessary, it wakes the check task up.
|
||||||
* It returns 0 on normal cases, <0 if at least one close() has happened on the
|
|
||||||
* connection (eg: reconnect). It relies on tcpcheck_main().
|
|
||||||
*/
|
*/
|
||||||
int wake_srv_chk(struct stconn *sc)
|
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state)
|
||||||
{
|
{
|
||||||
|
struct stconn *sc = ctx;
|
||||||
struct connection *conn;
|
struct connection *conn;
|
||||||
struct check *check = __sc_check(sc);
|
struct check *check = __sc_check(sc);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
@ -1099,15 +1097,6 @@ int wake_srv_chk(struct stconn *sc)
|
||||||
|
|
||||||
end:
|
end:
|
||||||
TRACE_LEAVE(CHK_EV_HCHK_WAKE, check);
|
TRACE_LEAVE(CHK_EV_HCHK_WAKE, check);
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function checks if any I/O is wanted, and if so, attempts to do so */
|
|
||||||
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state)
|
|
||||||
{
|
|
||||||
struct stconn *sc = ctx;
|
|
||||||
|
|
||||||
wake_srv_chk(sc);
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1526,14 +1515,16 @@ int check_buf_available(void *target)
|
||||||
/*
|
/*
|
||||||
* Allocate a buffer. If it fails, it adds the check in buffer wait queue.
|
* Allocate a buffer. If it fails, it adds the check in buffer wait queue.
|
||||||
*/
|
*/
|
||||||
struct buffer *check_get_buf(struct check *check, struct buffer *bptr)
|
struct buffer *check_get_buf(struct check *check, struct buffer *bptr, unsigned int small_buffer)
|
||||||
{
|
{
|
||||||
struct buffer *buf = NULL;
|
struct buffer *buf = NULL;
|
||||||
|
|
||||||
|
if (small_buffer == 0 || (buf = b_alloc_small(bptr)) == NULL) {
|
||||||
if (likely(!LIST_INLIST(&check->buf_wait.list)) &&
|
if (likely(!LIST_INLIST(&check->buf_wait.list)) &&
|
||||||
unlikely((buf = b_alloc(bptr, DB_CHANNEL)) == NULL)) {
|
unlikely((buf = b_alloc(bptr, DB_CHANNEL)) == NULL)) {
|
||||||
b_queue(DB_CHANNEL, &check->buf_wait, check, check_buf_available);
|
b_queue(DB_CHANNEL, &check->buf_wait, check, check_buf_available);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1544,7 +1535,10 @@ struct buffer *check_get_buf(struct check *check, struct buffer *bptr)
|
||||||
void check_release_buf(struct check *check, struct buffer *bptr)
|
void check_release_buf(struct check *check, struct buffer *bptr)
|
||||||
{
|
{
|
||||||
if (bptr->size) {
|
if (bptr->size) {
|
||||||
|
int defbuf = b_is_default(bptr);
|
||||||
|
|
||||||
b_free(bptr);
|
b_free(bptr);
|
||||||
|
if (defbuf)
|
||||||
offer_buffers(check->buf_wait.target, 1);
|
offer_buffers(check->buf_wait.target, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1665,7 +1659,6 @@ int start_check_task(struct check *check, int mininter,
|
||||||
*/
|
*/
|
||||||
static int start_checks()
|
static int start_checks()
|
||||||
{
|
{
|
||||||
|
|
||||||
struct proxy *px;
|
struct proxy *px;
|
||||||
struct server *s;
|
struct server *s;
|
||||||
char *errmsg = NULL;
|
char *errmsg = NULL;
|
||||||
|
|
@ -1692,6 +1685,10 @@ static int start_checks()
|
||||||
*/
|
*/
|
||||||
for (px = proxies_list; px; px = px->next) {
|
for (px = proxies_list; px; px = px->next) {
|
||||||
for (s = px->srv; s; s = s->next) {
|
for (s = px->srv; s; s = s->next) {
|
||||||
|
if ((px->options2 & PR_O2_USE_SBUF_CHECK) &&
|
||||||
|
(s->check.tcpcheck_rules->flags & TCPCHK_RULES_MAY_USE_SBUF))
|
||||||
|
s->check.state |= CHK_ST_USE_SMALL_BUFF;
|
||||||
|
|
||||||
if (s->check.state & CHK_ST_CONFIGURED) {
|
if (s->check.state & CHK_ST_CONFIGURED) {
|
||||||
nbcheck++;
|
nbcheck++;
|
||||||
if ((srv_getinter(&s->check) >= SRV_CHK_INTER_THRES) &&
|
if ((srv_getinter(&s->check) >= SRV_CHK_INTER_THRES) &&
|
||||||
|
|
@ -1816,7 +1813,15 @@ int init_srv_check(struct server *srv)
|
||||||
* specified.
|
* specified.
|
||||||
*/
|
*/
|
||||||
if (!srv->check.port && !is_addr(&srv->check.addr)) {
|
if (!srv->check.port && !is_addr(&srv->check.addr)) {
|
||||||
if (!srv->check.use_ssl && srv->use_ssl != -1)
|
/*
|
||||||
|
* If any setting is set for the check, then we can't
|
||||||
|
* assume we'll use the same XPRT as the server, the
|
||||||
|
* server may be QUIC, but we want a TCP check.
|
||||||
|
*/
|
||||||
|
if (!srv->check.use_ssl && srv->use_ssl != -1 &&
|
||||||
|
!srv->check.via_socks4 && !srv->check.send_proxy &&
|
||||||
|
(!srv->check.alpn_len || (srv->check.alpn_len == srv->ssl_ctx.alpn_len && !strncmp(srv->check.alpn_str, srv->ssl_ctx.alpn_str, srv->check.alpn_len))) &&
|
||||||
|
(!srv->check.mux_proto || srv->check.mux_proto != srv->mux_proto))
|
||||||
srv->check.xprt = srv->xprt;
|
srv->check.xprt = srv->xprt;
|
||||||
else if (srv->check.use_ssl == 1)
|
else if (srv->check.use_ssl == 1)
|
||||||
srv->check.xprt = xprt_get(XPRT_SSL);
|
srv->check.xprt = xprt_get(XPRT_SSL);
|
||||||
|
|
@ -2067,6 +2072,7 @@ static int srv_parse_addr(char **args, int *cur_arg, struct proxy *curpx, struct
|
||||||
char **errmsg)
|
char **errmsg)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage *sk;
|
struct sockaddr_storage *sk;
|
||||||
|
struct protocol *proto;
|
||||||
int port1, port2, err_code = 0;
|
int port1, port2, err_code = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2075,7 +2081,7 @@ static int srv_parse_addr(char **args, int *cur_arg, struct proxy *curpx, struct
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
sk = str2sa_range(args[*cur_arg+1], NULL, &port1, &port2, NULL, NULL, NULL, errmsg, NULL, NULL, NULL,
|
sk = str2sa_range(args[*cur_arg+1], NULL, &port1, &port2, NULL, &proto, NULL, errmsg, NULL, NULL, NULL,
|
||||||
PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT);
|
PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT);
|
||||||
if (!sk) {
|
if (!sk) {
|
||||||
memprintf(errmsg, "'%s' : %s", args[*cur_arg], *errmsg);
|
memprintf(errmsg, "'%s' : %s", args[*cur_arg], *errmsg);
|
||||||
|
|
@ -2083,6 +2089,7 @@ static int srv_parse_addr(char **args, int *cur_arg, struct proxy *curpx, struct
|
||||||
}
|
}
|
||||||
|
|
||||||
srv->check.addr = *sk;
|
srv->check.addr = *sk;
|
||||||
|
srv->check.proto = proto;
|
||||||
/* if agentaddr was never set, we can use addr */
|
/* if agentaddr was never set, we can use addr */
|
||||||
if (!(srv->flags & SRV_F_AGENTADDR))
|
if (!(srv->flags & SRV_F_AGENTADDR))
|
||||||
srv->agent.addr = *sk;
|
srv->agent.addr = *sk;
|
||||||
|
|
@ -2112,7 +2119,11 @@ static int srv_parse_agent_addr(char **args, int *cur_arg, struct proxy *curpx,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
set_srv_agent_addr(srv, &sk);
|
set_srv_agent_addr(srv, &sk);
|
||||||
|
/* Agent currently only uses TCP */
|
||||||
|
if (sk.ss_family == AF_INET)
|
||||||
|
srv->agent.proto = &proto_tcpv4;
|
||||||
|
else
|
||||||
|
srv->agent.proto = &proto_tcpv6;
|
||||||
out:
|
out:
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
|
|
|
||||||
97
src/chunk.c
97
src/chunk.c
|
|
@ -53,6 +53,22 @@ struct pool_head *pool_head_large_trash __read_mostly = NULL;
|
||||||
/* this is used to drain data, and as a temporary large buffer */
|
/* this is used to drain data, and as a temporary large buffer */
|
||||||
THREAD_LOCAL struct buffer trash_large = { };
|
THREAD_LOCAL struct buffer trash_large = { };
|
||||||
|
|
||||||
|
/* small trash chunks used for various conversions */
|
||||||
|
static THREAD_LOCAL struct buffer *small_trash_chunk;
|
||||||
|
static THREAD_LOCAL struct buffer small_trash_chunk1;
|
||||||
|
static THREAD_LOCAL struct buffer small_trash_chunk2;
|
||||||
|
|
||||||
|
/* small trash buffers used for various conversions */
|
||||||
|
static int small_trash_size __read_mostly = 0;
|
||||||
|
static THREAD_LOCAL char *small_trash_buf1 = NULL;
|
||||||
|
static THREAD_LOCAL char *small_trash_buf2 = NULL;
|
||||||
|
|
||||||
|
/* the trash pool for reentrant allocations */
|
||||||
|
struct pool_head *pool_head_small_trash __read_mostly = NULL;
|
||||||
|
|
||||||
|
/* this is used to drain data, and as a temporary small buffer */
|
||||||
|
THREAD_LOCAL struct buffer trash_small = { };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a pre-allocated and initialized trash chunk that can be used for any
|
* Returns a pre-allocated and initialized trash chunk that can be used for any
|
||||||
* type of conversion. Two chunks and their respective buffers are alternatively
|
* type of conversion. Two chunks and their respective buffers are alternatively
|
||||||
|
|
@ -103,14 +119,40 @@ struct buffer *get_large_trash_chunk(void)
|
||||||
return large_trash_chunk;
|
return large_trash_chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Similar to get_trash_chunk() but return a pre-allocated small chunk
|
||||||
|
* instead. Becasuse small buffers are not enabled by default, this function may
|
||||||
|
* return NULL.
|
||||||
|
*/
|
||||||
|
struct buffer *get_small_trash_chunk(void)
|
||||||
|
{
|
||||||
|
char *small_trash_buf;
|
||||||
|
|
||||||
|
if (!small_trash_size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (small_trash_chunk == &small_trash_chunk1) {
|
||||||
|
small_trash_chunk = &small_trash_chunk2;
|
||||||
|
small_trash_buf = small_trash_buf2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
small_trash_chunk = &small_trash_chunk1;
|
||||||
|
small_trash_buf = small_trash_buf1;
|
||||||
|
}
|
||||||
|
*small_trash_buf = 0;
|
||||||
|
chunk_init(small_trash_chunk, small_trash_buf, small_trash_size);
|
||||||
|
return small_trash_chunk;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns a trash chunk accordingly to the requested size. This function may
|
/* Returns a trash chunk accordingly to the requested size. This function may
|
||||||
* fail if the requested size is too big or if the large chubks are not
|
* fail if the requested size is too big or if the large chubks are not
|
||||||
* configured.
|
* configured.
|
||||||
*/
|
*/
|
||||||
struct buffer *get_trash_chunk_sz(size_t size)
|
struct buffer *get_trash_chunk_sz(size_t size)
|
||||||
{
|
{
|
||||||
if (likely(size <= trash_size))
|
if (likely(size > small_trash_size && size <= trash_size))
|
||||||
return get_trash_chunk();
|
return get_trash_chunk();
|
||||||
|
else if (small_trash_size && size <= small_trash_size)
|
||||||
|
return get_small_trash_chunk();
|
||||||
else if (large_trash_size && size <= large_trash_size)
|
else if (large_trash_size && size <= large_trash_size)
|
||||||
return get_large_trash_chunk();
|
return get_large_trash_chunk();
|
||||||
else
|
else
|
||||||
|
|
@ -122,17 +164,20 @@ struct buffer *get_trash_chunk_sz(size_t size)
|
||||||
*/
|
*/
|
||||||
struct buffer *get_larger_trash_chunk(struct buffer *chk)
|
struct buffer *get_larger_trash_chunk(struct buffer *chk)
|
||||||
{
|
{
|
||||||
struct buffer *chunk;
|
struct buffer *chunk = NULL;
|
||||||
|
|
||||||
if (!chk)
|
|
||||||
return get_trash_chunk();
|
|
||||||
|
|
||||||
/* No large buffers or current chunk is alread a large trash chunk */
|
|
||||||
if (!large_trash_size || chk->size == large_trash_size)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
|
if (!chk || chk->size == small_trash_size) {
|
||||||
|
/* no chunk or a small one, use a regular buffer */
|
||||||
|
chunk = get_trash_chunk();
|
||||||
|
}
|
||||||
|
else if (large_trash_size && chk->size <= large_trash_size) {
|
||||||
|
/* a regular byffer, use a large buffer if possible */
|
||||||
chunk = get_large_trash_chunk();
|
chunk = get_large_trash_chunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chk && chunk)
|
||||||
b_xfer(chunk, chk, b_data(chk));
|
b_xfer(chunk, chk, b_data(chk));
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,9 +211,29 @@ static int alloc_large_trash_buffers(int bufsize)
|
||||||
return trash_large.area && large_trash_buf1 && large_trash_buf2;
|
return trash_large.area && large_trash_buf1 && large_trash_buf2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* allocates the trash small buffers if necessary. Returns 0 in case of
|
||||||
|
* failure. Unlike alloc_trash_buffers(), It is unexpected to call this function
|
||||||
|
* multiple times. Small buffers are not used during configuration parsing.
|
||||||
|
*/
|
||||||
|
static int alloc_small_trash_buffers(int bufsize)
|
||||||
|
{
|
||||||
|
small_trash_size = bufsize;
|
||||||
|
if (!small_trash_size)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
BUG_ON(trash_small.area && small_trash_buf1 && small_trash_buf2);
|
||||||
|
|
||||||
|
chunk_init(&trash_small, my_realloc2(trash_small.area, bufsize), bufsize);
|
||||||
|
small_trash_buf1 = (char *)my_realloc2(small_trash_buf1, bufsize);
|
||||||
|
small_trash_buf2 = (char *)my_realloc2(small_trash_buf2, bufsize);
|
||||||
|
return trash_small.area && small_trash_buf1 && small_trash_buf2;
|
||||||
|
}
|
||||||
|
|
||||||
static int alloc_trash_buffers_per_thread()
|
static int alloc_trash_buffers_per_thread()
|
||||||
{
|
{
|
||||||
return alloc_trash_buffers(global.tune.bufsize) && alloc_large_trash_buffers(global.tune.bufsize_large);
|
return (alloc_trash_buffers(global.tune.bufsize) &&
|
||||||
|
alloc_large_trash_buffers(global.tune.bufsize_large) &&
|
||||||
|
alloc_small_trash_buffers(global.tune.bufsize_large));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_trash_buffers_per_thread()
|
static void free_trash_buffers_per_thread()
|
||||||
|
|
@ -180,6 +245,10 @@ static void free_trash_buffers_per_thread()
|
||||||
chunk_destroy(&trash_large);
|
chunk_destroy(&trash_large);
|
||||||
ha_free(&large_trash_buf2);
|
ha_free(&large_trash_buf2);
|
||||||
ha_free(&large_trash_buf1);
|
ha_free(&large_trash_buf1);
|
||||||
|
|
||||||
|
chunk_destroy(&trash_small);
|
||||||
|
ha_free(&small_trash_buf2);
|
||||||
|
ha_free(&small_trash_buf1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the trash buffers. It returns 0 if an error occurred. */
|
/* Initialize the trash buffers. It returns 0 if an error occurred. */
|
||||||
|
|
@ -207,6 +276,14 @@ int init_trash_buffers(int first)
|
||||||
if (!pool_head_large_trash)
|
if (!pool_head_large_trash)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!first && global.tune.bufsize_small) {
|
||||||
|
pool_head_small_trash = create_pool("small_trash",
|
||||||
|
sizeof(struct buffer) + global.tune.bufsize_small,
|
||||||
|
MEM_F_EXACT);
|
||||||
|
if (!pool_head_small_trash)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue