blob: 895a1306fd230207e85c0f3c9988e9525f6da44a [file] [log] [blame]
Willy Tarreau8987e7a2020-08-28 11:37:21 +02001/*
2 * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp)
3 *
4 * Copyright 2000-2013 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13/* this is to have tcp_info defined on systems using musl
14 * library, such as Alpine Linux.
15 */
16#define _GNU_SOURCE
17
18#include <ctype.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <time.h>
25
26#include <sys/param.h>
27#include <sys/socket.h>
28#include <sys/types.h>
29
30#include <netinet/tcp.h>
31#include <netinet/in.h>
32
33#include <haproxy/api.h>
34#include <haproxy/arg.h>
35#include <haproxy/connection.h>
Willy Tarreau6cd007d2021-10-06 19:01:21 +020036#include <haproxy/errors.h>
Willy Tarreau8987e7a2020-08-28 11:37:21 +020037#include <haproxy/global.h>
38#include <haproxy/listener-t.h>
39#include <haproxy/namespace.h>
40#include <haproxy/proxy-t.h>
41#include <haproxy/sample.h>
Christopher Fauletc03be1a2021-10-25 08:01:20 +020042#include <haproxy/session.h>
43#include <haproxy/stream_interface.h>
Willy Tarreau8987e7a2020-08-28 11:37:21 +020044#include <haproxy/tools.h>
45
Christopher Faulet7d081f02021-04-15 09:38:37 +020046/* Fetch the connection's source IPv4/IPv6 address. Depending on the keyword, it
47 * may be the frontend or the backend connection.
Willy Tarreau8987e7a2020-08-28 11:37:21 +020048 */
49static int
50smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private)
51{
Christopher Fauletc03be1a2021-10-25 08:01:20 +020052 const struct sockaddr_storage *src = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +020053
Christopher Faulet888cd702021-10-25 16:58:50 +020054 if (kw[0] == 'b') { /* bc_src */
Christopher Fauletc03be1a2021-10-25 08:01:20 +020055 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
56 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +010057 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +020058 if (conn && conn_get_src(conn))
59 src = conn_src(conn);
60 }
Christopher Faulet888cd702021-10-25 16:58:50 +020061 else if (kw[0] == 'f') { /* fc_src */
62 struct connection *conn = objt_conn(smp->sess->origin);
63
64 if (conn && conn_get_src(conn))
65 src = conn_src(conn);
66 }
67 else /* src */
Christopher Fauletcda94ac2021-12-23 17:28:17 +010068 src = (smp->strm ? si_src(smp->strm->csf->si) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +020069
Christopher Fauletc03be1a2021-10-25 08:01:20 +020070 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +020071 return 0;
72
Christopher Fauletc03be1a2021-10-25 08:01:20 +020073 switch (src->ss_family) {
Willy Tarreau8987e7a2020-08-28 11:37:21 +020074 case AF_INET:
Christopher Fauletc03be1a2021-10-25 08:01:20 +020075 smp->data.u.ipv4 = ((struct sockaddr_in *)src)->sin_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +020076 smp->data.type = SMP_T_IPV4;
77 break;
78 case AF_INET6:
Christopher Fauletc03be1a2021-10-25 08:01:20 +020079 smp->data.u.ipv6 = ((struct sockaddr_in6 *)src)->sin6_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +020080 smp->data.type = SMP_T_IPV6;
81 break;
82 default:
83 return 0;
84 }
85
86 smp->flags = 0;
87 return 1;
88}
89
Christopher Faulet7d081f02021-04-15 09:38:37 +020090/* set temp integer to the connection's source port. Depending on the
91 * keyword, it may be the frontend or the backend connection.
92 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +020093static int
Christopher Faulet7d081f02021-04-15 09:38:37 +020094smp_fetch_sport(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8987e7a2020-08-28 11:37:21 +020095{
Christopher Fauletc03be1a2021-10-25 08:01:20 +020096 const struct sockaddr_storage *src = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +020097
Christopher Faulet888cd702021-10-25 16:58:50 +020098 if (kw[0] == 'b') { /* bc_src_port */
Christopher Fauletc03be1a2021-10-25 08:01:20 +020099 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
100 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100101 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200102 if (conn && conn_get_src(conn))
103 src = conn_src(conn);
104 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200105 else if (kw[0] == 'f') { /* fc_src_port */
106 struct connection *conn = objt_conn(smp->sess->origin);
107
108 if (conn && conn_get_src(conn))
109 src = conn_src(conn);
110 }
111 else /* src_port */
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100112 src = (smp->strm ? si_src(smp->strm->csf->si) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200113
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200114 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200115 return 0;
116
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200117 smp->data.type = SMP_T_SINT;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200118 if (!(smp->data.u.sint = get_host_port(src)))
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200119 return 0;
120
121 smp->flags = 0;
122 return 1;
123}
124
Christopher Faulet7d081f02021-04-15 09:38:37 +0200125/* fetch the connection's destination IPv4/IPv6 address. Depending on the
126 * keyword, it may be the frontend or the backend connection.
127 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200128static int
129smp_fetch_dst(const struct arg *args, struct sample *smp, const char *kw, void *private)
130{
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200131 const struct sockaddr_storage *dst = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +0200132
Christopher Faulet888cd702021-10-25 16:58:50 +0200133 if (kw[0] == 'b') { /* bc_dst */
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200134 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
135 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100136 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200137 if (conn && conn_get_dst(conn))
138 dst = conn_dst(conn);
139 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200140 else if (kw[0] == 'f') { /* fc_dst */
141 struct connection *conn = objt_conn(smp->sess->origin);
142
143 if (conn && conn_get_dst(conn))
144 dst = conn_dst(conn);
145 }
146 else /* dst */
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100147 dst = (smp->strm ? si_dst(smp->strm->csf->si) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200148
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200149 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200150 return 0;
151
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200152 switch (dst->ss_family) {
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200153 case AF_INET:
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200154 smp->data.u.ipv4 = ((struct sockaddr_in *)dst)->sin_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200155 smp->data.type = SMP_T_IPV4;
156 break;
157 case AF_INET6:
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200158 smp->data.u.ipv6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200159 smp->data.type = SMP_T_IPV6;
160 break;
161 default:
162 return 0;
163 }
164
165 smp->flags = 0;
166 return 1;
167}
168
169/* check if the destination address of the front connection is local to the
170 * system or if it was intercepted.
171 */
172int smp_fetch_dst_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
173{
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200174 struct listener *li = smp->sess->listener;
Christopher Faulet888cd702021-10-25 16:58:50 +0200175 const struct sockaddr_storage *dst = NULL;
176
177 if (kw[0] == 'f') { /* fc_dst_is_local */
178 struct connection *conn = objt_conn(smp->sess->origin);
179
180 if (conn && conn_get_src(conn))
181 dst = conn_dst(conn);
182 }
183 else /* dst_is_local */
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100184 dst = (smp->strm ? si_dst(smp->strm->csf->si) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200185
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200186 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200187 return 0;
188
189 smp->data.type = SMP_T_BOOL;
190 smp->flags = 0;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200191 smp->data.u.sint = addr_is_local(li->rx.settings->netns, dst);
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200192 return smp->data.u.sint >= 0;
193}
194
195/* check if the source address of the front connection is local to the system
196 * or not.
197 */
198int smp_fetch_src_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
199{
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200200 struct listener *li = smp->sess->listener;
Christopher Faulet888cd702021-10-25 16:58:50 +0200201 const struct sockaddr_storage *src = NULL;
202
203 if (kw[0] == 'f') { /* fc_src_is_local */
204 struct connection *conn = objt_conn(smp->sess->origin);
205
206 if (conn && conn_get_src(conn))
207 src = conn_src(conn);
208 }
209 else /* src_is_local */
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100210 src = (smp->strm ? si_src(smp->strm->csf->si) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200211
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200212 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200213 return 0;
214
215 smp->data.type = SMP_T_BOOL;
216 smp->flags = 0;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200217 smp->data.u.sint = addr_is_local(li->rx.settings->netns, src);
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200218 return smp->data.u.sint >= 0;
219}
220
Christopher Faulet7d081f02021-04-15 09:38:37 +0200221/* set temp integer to the connexion's destination port. Depending on the
222 * keyword, it may be the frontend or the backend connection.
223 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200224static int
225smp_fetch_dport(const struct arg *args, struct sample *smp, const char *kw, void *private)
226{
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200227 const struct sockaddr_storage *dst = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +0200228
Christopher Faulet888cd702021-10-25 16:58:50 +0200229 if (kw[0] == 'b') { /* bc_dst_port */
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200230 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
231 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100232 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200233 if (conn && conn_get_dst(conn))
234 dst = conn_dst(conn);
235 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200236 else if (kw[0] == 'f') { /* fc_dst_post */
237 struct connection *conn = objt_conn(smp->sess->origin);
238
239 if (conn && conn_get_src(conn))
240 dst = conn_dst(conn);
241 }
242 else /* dst_port */
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100243 dst = (smp->strm ? si_dst(smp->strm->csf->si) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200244
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200245 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200246 return 0;
247
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200248 smp->data.type = SMP_T_SINT;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200249 if (!(smp->data.u.sint = get_host_port(dst)))
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200250 return 0;
251
252 smp->flags = 0;
253 return 1;
254}
255
256#ifdef TCP_INFO
257
258
259/* Validates the arguments passed to "fc_*" fetch keywords returning a time
260 * value. These keywords support an optional string representing the unit of the
261 * result: "us" for microseconds and "ms" for milliseconds". Returns 0 on error
262 * and non-zero if OK.
263 */
264static int val_fc_time_value(struct arg *args, char **err)
265{
266 if (args[0].type == ARGT_STR) {
267 if (strcmp(args[0].data.str.area, "us") == 0) {
268 chunk_destroy(&args[0].data.str);
269 args[0].type = ARGT_SINT;
270 args[0].data.sint = TIME_UNIT_US;
271 }
272 else if (strcmp(args[0].data.str.area, "ms") == 0) {
273 chunk_destroy(&args[0].data.str);
274 args[0].type = ARGT_SINT;
275 args[0].data.sint = TIME_UNIT_MS;
276 }
277 else {
278 memprintf(err, "expects 'us' or 'ms', got '%s'",
279 args[0].data.str.area);
280 return 0;
281 }
282 }
283 else {
284 memprintf(err, "Unexpected arg type");
285 return 0;
286 }
287
288 return 1;
289}
290
291/* Validates the arguments passed to "fc_*" fetch keywords returning a
292 * counter. These keywords should be used without any keyword, but because of a
293 * bug in previous versions, an optional string argument may be passed. In such
294 * case, the argument is ignored and a warning is emitted. Returns 0 on error
295 * and non-zero if OK.
296 */
297static int var_fc_counter(struct arg *args, char **err)
298{
299 if (args[0].type != ARGT_STOP) {
300 ha_warning("no argument supported for 'fc_*' sample expressions returning counters.\n");
301 if (args[0].type == ARGT_STR)
302 chunk_destroy(&args[0].data.str);
303 args[0].type = ARGT_STOP;
304 }
305
306 return 1;
307}
308
309/* Returns some tcp_info data if it's available. "dir" must be set to 0 if
310 * the client connection is required, otherwise it is set to 1. "val" represents
311 * the required value.
312 * If the function fails it returns 0, otherwise it returns 1 and "result" is filled.
313 */
314static inline int get_tcp_info(const struct arg *args, struct sample *smp,
315 int dir, int val)
316{
317 struct connection *conn;
318 struct tcp_info info;
319 socklen_t optlen;
320
321 /* strm can be null. */
322 if (!smp->strm)
323 return 0;
324
325 /* get the object associated with the stream interface.The
326 * object can be other thing than a connection. For example,
327 * it be a appctx. */
Christopher Faulet95a61e82021-12-22 14:22:03 +0100328 conn = (dir == 0 ? cs_conn(smp->strm->csf) : cs_conn(smp->strm->csb));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200329 if (!conn)
330 return 0;
331
332 /* The fd may not be available for the tcp_info struct, and the
333 syscal can fail. */
334 optlen = sizeof(info);
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200335 if (getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &info, &optlen) == -1)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200336 return 0;
337
338 /* extract the value. */
339 smp->data.type = SMP_T_SINT;
340 switch (val) {
341 case 0: smp->data.u.sint = info.tcpi_rtt; break;
342 case 1: smp->data.u.sint = info.tcpi_rttvar; break;
343#if defined(__linux__)
344 /* these ones are common to all Linux versions */
345 case 2: smp->data.u.sint = info.tcpi_unacked; break;
346 case 3: smp->data.u.sint = info.tcpi_sacked; break;
347 case 4: smp->data.u.sint = info.tcpi_lost; break;
348 case 5: smp->data.u.sint = info.tcpi_retrans; break;
349 case 6: smp->data.u.sint = info.tcpi_fackets; break;
350 case 7: smp->data.u.sint = info.tcpi_reordering; break;
351#elif defined(__FreeBSD__) || defined(__NetBSD__)
352 /* the ones are found on FreeBSD and NetBSD featuring TCP_INFO */
353 case 2: smp->data.u.sint = info.__tcpi_unacked; break;
354 case 3: smp->data.u.sint = info.__tcpi_sacked; break;
355 case 4: smp->data.u.sint = info.__tcpi_lost; break;
356 case 5: smp->data.u.sint = info.__tcpi_retrans; break;
357 case 6: smp->data.u.sint = info.__tcpi_fackets; break;
358 case 7: smp->data.u.sint = info.__tcpi_reordering; break;
359#endif
360 default: return 0;
361 }
362
363 return 1;
364}
365
366/* get the mean rtt of a client connection */
367static int
368smp_fetch_fc_rtt(const struct arg *args, struct sample *smp, const char *kw, void *private)
369{
370 if (!get_tcp_info(args, smp, 0, 0))
371 return 0;
372
373 /* By default or if explicitly specified, convert rtt to ms */
374 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
375 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
376
377 return 1;
378}
379
380/* get the variance of the mean rtt of a client connection */
381static int
382smp_fetch_fc_rttvar(const struct arg *args, struct sample *smp, const char *kw, void *private)
383{
384 if (!get_tcp_info(args, smp, 0, 1))
385 return 0;
386
387 /* By default or if explicitly specified, convert rttvar to ms */
388 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
389 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
390
391 return 1;
392}
393
394#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
395
396/* get the unacked counter on a client connection */
397static int
398smp_fetch_fc_unacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
399{
400 if (!get_tcp_info(args, smp, 0, 2))
401 return 0;
402 return 1;
403}
404
405/* get the sacked counter on a client connection */
406static int
407smp_fetch_fc_sacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
408{
409 if (!get_tcp_info(args, smp, 0, 3))
410 return 0;
411 return 1;
412}
413
414/* get the lost counter on a client connection */
415static int
416smp_fetch_fc_lost(const struct arg *args, struct sample *smp, const char *kw, void *private)
417{
418 if (!get_tcp_info(args, smp, 0, 4))
419 return 0;
420 return 1;
421}
422
423/* get the retrans counter on a client connection */
424static int
425smp_fetch_fc_retrans(const struct arg *args, struct sample *smp, const char *kw, void *private)
426{
427 if (!get_tcp_info(args, smp, 0, 5))
428 return 0;
429 return 1;
430}
431
432/* get the fackets counter on a client connection */
433static int
434smp_fetch_fc_fackets(const struct arg *args, struct sample *smp, const char *kw, void *private)
435{
436 if (!get_tcp_info(args, smp, 0, 6))
437 return 0;
438 return 1;
439}
440
441/* get the reordering counter on a client connection */
442static int
443smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char *kw, void *private)
444{
445 if (!get_tcp_info(args, smp, 0, 7))
446 return 0;
447 return 1;
448}
449#endif // linux || freebsd || netbsd
450#endif // TCP_INFO
451
452/* Note: must not be declared <const> as its list will be overwritten.
453 * Note: fetches that may return multiple types must be declared as the lowest
454 * common denominator, the type that can be casted into all other ones. For
455 * instance v4/v6 must be declared v4.
456 */
457static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
Christopher Faulet7d081f02021-04-15 09:38:37 +0200458 { "bc_dst", smp_fetch_dst, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
459 { "bc_dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
460 { "bc_src", smp_fetch_src, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
461 { "bc_src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
462
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200463 { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
464 { "dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
465 { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
Christopher Faulet888cd702021-10-25 16:58:50 +0200466
467 { "fc_dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
468 { "fc_dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
469 { "fc_dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
470
471 { "fc_src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
472 { "fc_src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
473 { "fc_src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
474
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200475 { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
476 { "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
477 { "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
478#ifdef TCP_INFO
479 { "fc_rtt", smp_fetch_fc_rtt, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
480 { "fc_rttvar", smp_fetch_fc_rttvar, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
481#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
482 { "fc_unacked", smp_fetch_fc_unacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
483 { "fc_sacked", smp_fetch_fc_sacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
484 { "fc_retrans", smp_fetch_fc_retrans, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
485 { "fc_fackets", smp_fetch_fc_fackets, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
486 { "fc_lost", smp_fetch_fc_lost, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
487 { "fc_reordering", smp_fetch_fc_reordering, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
488#endif // linux || freebsd || netbsd
489#endif // TCP_INFO
490 { /* END */ },
491}};
492
493INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
494
495
496/*
497 * Local variables:
498 * c-indent-level: 8
499 * c-basic-offset: 8
500 * End:
501 */