blob: fe10fc2cf78deb8c6c7b31f126851323579a128e [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>
Christopher Faulet8da67aa2022-03-29 17:53:09 +020036#include <haproxy/cs_utils.h>
Willy Tarreau6cd007d2021-10-06 19:01:21 +020037#include <haproxy/errors.h>
Willy Tarreau8987e7a2020-08-28 11:37:21 +020038#include <haproxy/global.h>
39#include <haproxy/listener-t.h>
40#include <haproxy/namespace.h>
41#include <haproxy/proxy-t.h>
42#include <haproxy/sample.h>
Christopher Fauletc03be1a2021-10-25 08:01:20 +020043#include <haproxy/session.h>
44#include <haproxy/stream_interface.h>
Willy Tarreau8987e7a2020-08-28 11:37:21 +020045#include <haproxy/tools.h>
46
Christopher Faulet7d081f02021-04-15 09:38:37 +020047/* Fetch the connection's source IPv4/IPv6 address. Depending on the keyword, it
48 * may be the frontend or the backend connection.
Willy Tarreau8987e7a2020-08-28 11:37:21 +020049 */
50static int
51smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private)
52{
Christopher Fauletc03be1a2021-10-25 08:01:20 +020053 const struct sockaddr_storage *src = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +020054
Christopher Faulet888cd702021-10-25 16:58:50 +020055 if (kw[0] == 'b') { /* bc_src */
Christopher Fauletc03be1a2021-10-25 08:01:20 +020056 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
57 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +010058 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +020059 if (conn && conn_get_src(conn))
60 src = conn_src(conn);
61 }
Christopher Faulet888cd702021-10-25 16:58:50 +020062 else if (kw[0] == 'f') { /* fc_src */
63 struct connection *conn = objt_conn(smp->sess->origin);
64
65 if (conn && conn_get_src(conn))
66 src = conn_src(conn);
67 }
68 else /* src */
Christopher Faulet8da67aa2022-03-29 17:53:09 +020069 src = (smp->strm ? cs_src(smp->strm->csf) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +020070
Christopher Fauletc03be1a2021-10-25 08:01:20 +020071 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +020072 return 0;
73
Christopher Fauletc03be1a2021-10-25 08:01:20 +020074 switch (src->ss_family) {
Willy Tarreau8987e7a2020-08-28 11:37:21 +020075 case AF_INET:
Christopher Fauletc03be1a2021-10-25 08:01:20 +020076 smp->data.u.ipv4 = ((struct sockaddr_in *)src)->sin_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +020077 smp->data.type = SMP_T_IPV4;
78 break;
79 case AF_INET6:
Christopher Fauletc03be1a2021-10-25 08:01:20 +020080 smp->data.u.ipv6 = ((struct sockaddr_in6 *)src)->sin6_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +020081 smp->data.type = SMP_T_IPV6;
82 break;
83 default:
84 return 0;
85 }
86
87 smp->flags = 0;
88 return 1;
89}
90
Christopher Faulet7d081f02021-04-15 09:38:37 +020091/* set temp integer to the connection's source port. Depending on the
92 * keyword, it may be the frontend or the backend connection.
93 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +020094static int
Christopher Faulet7d081f02021-04-15 09:38:37 +020095smp_fetch_sport(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8987e7a2020-08-28 11:37:21 +020096{
Christopher Fauletc03be1a2021-10-25 08:01:20 +020097 const struct sockaddr_storage *src = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +020098
Christopher Faulet888cd702021-10-25 16:58:50 +020099 if (kw[0] == 'b') { /* bc_src_port */
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200100 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
101 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100102 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200103 if (conn && conn_get_src(conn))
104 src = conn_src(conn);
105 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200106 else if (kw[0] == 'f') { /* fc_src_port */
107 struct connection *conn = objt_conn(smp->sess->origin);
108
109 if (conn && conn_get_src(conn))
110 src = conn_src(conn);
111 }
112 else /* src_port */
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200113 src = (smp->strm ? cs_src(smp->strm->csf) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200114
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200115 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200116 return 0;
117
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200118 smp->data.type = SMP_T_SINT;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200119 if (!(smp->data.u.sint = get_host_port(src)))
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200120 return 0;
121
122 smp->flags = 0;
123 return 1;
124}
125
Christopher Faulet7d081f02021-04-15 09:38:37 +0200126/* fetch the connection's destination IPv4/IPv6 address. Depending on the
127 * keyword, it may be the frontend or the backend connection.
128 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200129static int
130smp_fetch_dst(const struct arg *args, struct sample *smp, const char *kw, void *private)
131{
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200132 const struct sockaddr_storage *dst = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +0200133
Christopher Faulet888cd702021-10-25 16:58:50 +0200134 if (kw[0] == 'b') { /* bc_dst */
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200135 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
136 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100137 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200138 if (conn && conn_get_dst(conn))
139 dst = conn_dst(conn);
140 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200141 else if (kw[0] == 'f') { /* fc_dst */
142 struct connection *conn = objt_conn(smp->sess->origin);
143
144 if (conn && conn_get_dst(conn))
145 dst = conn_dst(conn);
146 }
147 else /* dst */
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200148 dst = (smp->strm ? cs_dst(smp->strm->csf) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200149
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200150 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200151 return 0;
152
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200153 switch (dst->ss_family) {
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200154 case AF_INET:
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200155 smp->data.u.ipv4 = ((struct sockaddr_in *)dst)->sin_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200156 smp->data.type = SMP_T_IPV4;
157 break;
158 case AF_INET6:
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200159 smp->data.u.ipv6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200160 smp->data.type = SMP_T_IPV6;
161 break;
162 default:
163 return 0;
164 }
165
166 smp->flags = 0;
167 return 1;
168}
169
170/* check if the destination address of the front connection is local to the
171 * system or if it was intercepted.
172 */
173int smp_fetch_dst_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
174{
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200175 struct listener *li = smp->sess->listener;
Christopher Faulet888cd702021-10-25 16:58:50 +0200176 const struct sockaddr_storage *dst = NULL;
177
178 if (kw[0] == 'f') { /* fc_dst_is_local */
179 struct connection *conn = objt_conn(smp->sess->origin);
180
181 if (conn && conn_get_src(conn))
182 dst = conn_dst(conn);
183 }
184 else /* dst_is_local */
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200185 dst = (smp->strm ? cs_dst(smp->strm->csf) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200186
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200187 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200188 return 0;
189
190 smp->data.type = SMP_T_BOOL;
191 smp->flags = 0;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200192 smp->data.u.sint = addr_is_local(li->rx.settings->netns, dst);
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200193 return smp->data.u.sint >= 0;
194}
195
196/* check if the source address of the front connection is local to the system
197 * or not.
198 */
199int smp_fetch_src_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
200{
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200201 struct listener *li = smp->sess->listener;
Christopher Faulet888cd702021-10-25 16:58:50 +0200202 const struct sockaddr_storage *src = NULL;
203
204 if (kw[0] == 'f') { /* fc_src_is_local */
205 struct connection *conn = objt_conn(smp->sess->origin);
206
207 if (conn && conn_get_src(conn))
208 src = conn_src(conn);
209 }
210 else /* src_is_local */
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200211 src = (smp->strm ? cs_src(smp->strm->csf) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200212
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200213 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200214 return 0;
215
216 smp->data.type = SMP_T_BOOL;
217 smp->flags = 0;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200218 smp->data.u.sint = addr_is_local(li->rx.settings->netns, src);
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200219 return smp->data.u.sint >= 0;
220}
221
Christopher Faulet7d081f02021-04-15 09:38:37 +0200222/* set temp integer to the connexion's destination port. Depending on the
223 * keyword, it may be the frontend or the backend connection.
224 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200225static int
226smp_fetch_dport(const struct arg *args, struct sample *smp, const char *kw, void *private)
227{
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200228 const struct sockaddr_storage *dst = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +0200229
Christopher Faulet888cd702021-10-25 16:58:50 +0200230 if (kw[0] == 'b') { /* bc_dst_port */
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200231 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
232 ? cs_conn(__objt_check(smp->sess->origin)->cs)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100233 : (smp->strm ? cs_conn(smp->strm->csb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200234 if (conn && conn_get_dst(conn))
235 dst = conn_dst(conn);
236 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200237 else if (kw[0] == 'f') { /* fc_dst_post */
238 struct connection *conn = objt_conn(smp->sess->origin);
239
240 if (conn && conn_get_src(conn))
241 dst = conn_dst(conn);
242 }
243 else /* dst_port */
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200244 dst = (smp->strm ? cs_dst(smp->strm->csf) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200245
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200246 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200247 return 0;
248
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200249 smp->data.type = SMP_T_SINT;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200250 if (!(smp->data.u.sint = get_host_port(dst)))
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200251 return 0;
252
253 smp->flags = 0;
254 return 1;
255}
256
257#ifdef TCP_INFO
258
259
260/* Validates the arguments passed to "fc_*" fetch keywords returning a time
261 * value. These keywords support an optional string representing the unit of the
262 * result: "us" for microseconds and "ms" for milliseconds". Returns 0 on error
263 * and non-zero if OK.
264 */
265static int val_fc_time_value(struct arg *args, char **err)
266{
267 if (args[0].type == ARGT_STR) {
268 if (strcmp(args[0].data.str.area, "us") == 0) {
269 chunk_destroy(&args[0].data.str);
270 args[0].type = ARGT_SINT;
271 args[0].data.sint = TIME_UNIT_US;
272 }
273 else if (strcmp(args[0].data.str.area, "ms") == 0) {
274 chunk_destroy(&args[0].data.str);
275 args[0].type = ARGT_SINT;
276 args[0].data.sint = TIME_UNIT_MS;
277 }
278 else {
279 memprintf(err, "expects 'us' or 'ms', got '%s'",
280 args[0].data.str.area);
281 return 0;
282 }
283 }
284 else {
285 memprintf(err, "Unexpected arg type");
286 return 0;
287 }
288
289 return 1;
290}
291
292/* Validates the arguments passed to "fc_*" fetch keywords returning a
293 * counter. These keywords should be used without any keyword, but because of a
294 * bug in previous versions, an optional string argument may be passed. In such
295 * case, the argument is ignored and a warning is emitted. Returns 0 on error
296 * and non-zero if OK.
297 */
298static int var_fc_counter(struct arg *args, char **err)
299{
300 if (args[0].type != ARGT_STOP) {
301 ha_warning("no argument supported for 'fc_*' sample expressions returning counters.\n");
302 if (args[0].type == ARGT_STR)
303 chunk_destroy(&args[0].data.str);
304 args[0].type = ARGT_STOP;
305 }
306
307 return 1;
308}
309
310/* Returns some tcp_info data if it's available. "dir" must be set to 0 if
311 * the client connection is required, otherwise it is set to 1. "val" represents
312 * the required value.
313 * If the function fails it returns 0, otherwise it returns 1 and "result" is filled.
314 */
315static inline int get_tcp_info(const struct arg *args, struct sample *smp,
316 int dir, int val)
317{
318 struct connection *conn;
319 struct tcp_info info;
320 socklen_t optlen;
321
322 /* strm can be null. */
323 if (!smp->strm)
324 return 0;
325
326 /* get the object associated with the stream interface.The
327 * object can be other thing than a connection. For example,
328 * it be a appctx. */
Christopher Faulet95a61e82021-12-22 14:22:03 +0100329 conn = (dir == 0 ? cs_conn(smp->strm->csf) : cs_conn(smp->strm->csb));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200330 if (!conn)
331 return 0;
332
333 /* The fd may not be available for the tcp_info struct, and the
334 syscal can fail. */
335 optlen = sizeof(info);
Willy Tarreaue2226792022-04-11 18:04:33 +0200336 if ((conn->flags & CO_FL_FDLESS) ||
337 getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &info, &optlen) == -1)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200338 return 0;
339
340 /* extract the value. */
341 smp->data.type = SMP_T_SINT;
342 switch (val) {
343 case 0: smp->data.u.sint = info.tcpi_rtt; break;
344 case 1: smp->data.u.sint = info.tcpi_rttvar; break;
345#if defined(__linux__)
346 /* these ones are common to all Linux versions */
347 case 2: smp->data.u.sint = info.tcpi_unacked; break;
348 case 3: smp->data.u.sint = info.tcpi_sacked; break;
349 case 4: smp->data.u.sint = info.tcpi_lost; break;
350 case 5: smp->data.u.sint = info.tcpi_retrans; break;
351 case 6: smp->data.u.sint = info.tcpi_fackets; break;
352 case 7: smp->data.u.sint = info.tcpi_reordering; break;
353#elif defined(__FreeBSD__) || defined(__NetBSD__)
354 /* the ones are found on FreeBSD and NetBSD featuring TCP_INFO */
355 case 2: smp->data.u.sint = info.__tcpi_unacked; break;
356 case 3: smp->data.u.sint = info.__tcpi_sacked; break;
357 case 4: smp->data.u.sint = info.__tcpi_lost; break;
358 case 5: smp->data.u.sint = info.__tcpi_retrans; break;
359 case 6: smp->data.u.sint = info.__tcpi_fackets; break;
360 case 7: smp->data.u.sint = info.__tcpi_reordering; break;
361#endif
362 default: return 0;
363 }
364
365 return 1;
366}
367
368/* get the mean rtt of a client connection */
369static int
370smp_fetch_fc_rtt(const struct arg *args, struct sample *smp, const char *kw, void *private)
371{
372 if (!get_tcp_info(args, smp, 0, 0))
373 return 0;
374
375 /* By default or if explicitly specified, convert rtt to ms */
376 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
377 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
378
379 return 1;
380}
381
382/* get the variance of the mean rtt of a client connection */
383static int
384smp_fetch_fc_rttvar(const struct arg *args, struct sample *smp, const char *kw, void *private)
385{
386 if (!get_tcp_info(args, smp, 0, 1))
387 return 0;
388
389 /* By default or if explicitly specified, convert rttvar to ms */
390 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
391 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
392
393 return 1;
394}
395
396#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
397
398/* get the unacked counter on a client connection */
399static int
400smp_fetch_fc_unacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
401{
402 if (!get_tcp_info(args, smp, 0, 2))
403 return 0;
404 return 1;
405}
406
407/* get the sacked counter on a client connection */
408static int
409smp_fetch_fc_sacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
410{
411 if (!get_tcp_info(args, smp, 0, 3))
412 return 0;
413 return 1;
414}
415
416/* get the lost counter on a client connection */
417static int
418smp_fetch_fc_lost(const struct arg *args, struct sample *smp, const char *kw, void *private)
419{
420 if (!get_tcp_info(args, smp, 0, 4))
421 return 0;
422 return 1;
423}
424
425/* get the retrans counter on a client connection */
426static int
427smp_fetch_fc_retrans(const struct arg *args, struct sample *smp, const char *kw, void *private)
428{
429 if (!get_tcp_info(args, smp, 0, 5))
430 return 0;
431 return 1;
432}
433
434/* get the fackets counter on a client connection */
435static int
436smp_fetch_fc_fackets(const struct arg *args, struct sample *smp, const char *kw, void *private)
437{
438 if (!get_tcp_info(args, smp, 0, 6))
439 return 0;
440 return 1;
441}
442
443/* get the reordering counter on a client connection */
444static int
445smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char *kw, void *private)
446{
447 if (!get_tcp_info(args, smp, 0, 7))
448 return 0;
449 return 1;
450}
451#endif // linux || freebsd || netbsd
452#endif // TCP_INFO
453
454/* Note: must not be declared <const> as its list will be overwritten.
455 * Note: fetches that may return multiple types must be declared as the lowest
456 * common denominator, the type that can be casted into all other ones. For
457 * instance v4/v6 must be declared v4.
458 */
459static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
Christopher Faulet7d081f02021-04-15 09:38:37 +0200460 { "bc_dst", smp_fetch_dst, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
461 { "bc_dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
462 { "bc_src", smp_fetch_src, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
463 { "bc_src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
464
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200465 { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
466 { "dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
467 { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
Christopher Faulet888cd702021-10-25 16:58:50 +0200468
469 { "fc_dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
470 { "fc_dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
471 { "fc_dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
472
473 { "fc_src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
474 { "fc_src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
475 { "fc_src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
476
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200477 { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
478 { "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
479 { "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
480#ifdef TCP_INFO
481 { "fc_rtt", smp_fetch_fc_rtt, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
482 { "fc_rttvar", smp_fetch_fc_rttvar, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
483#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
484 { "fc_unacked", smp_fetch_fc_unacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
485 { "fc_sacked", smp_fetch_fc_sacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
486 { "fc_retrans", smp_fetch_fc_retrans, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
487 { "fc_fackets", smp_fetch_fc_fackets, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
488 { "fc_lost", smp_fetch_fc_lost, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
489 { "fc_reordering", smp_fetch_fc_reordering, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
490#endif // linux || freebsd || netbsd
491#endif // TCP_INFO
492 { /* END */ },
493}};
494
495INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
496
497
498/*
499 * Local variables:
500 * c-indent-level: 8
501 * c-basic-offset: 8
502 * End:
503 */