2 * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
9 #include <common/buffer-view.h>
10 #include <common/dynamic-buffer.h>
11 #include <common/error.h>
12 #include <common/macros.h>
13 #include <common/payload-view.h>
14 #include <common/payload.h>
16 #include <lttng/action/rate-policy-internal.h>
17 #include <lttng/action/rate-policy.h>
19 #include <sys/types.h>
21 #define IS_EVERY_N_RATE_POLICY(policy) \
22 (lttng_rate_policy_get_type(policy) == LTTNG_RATE_POLICY_TYPE_EVERY_N)
24 #define IS_ONCE_AFTER_N_RATE_POLICY(policy) \
25 (lttng_rate_policy_get_type(policy) == \
26 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N)
28 typedef void (*rate_policy_destroy_cb
)(struct lttng_rate_policy
*rate_policy
);
29 typedef int (*rate_policy_serialize_cb
)(struct lttng_rate_policy
*rate_policy
,
30 struct lttng_payload
*payload
);
31 typedef bool (*rate_policy_equal_cb
)(const struct lttng_rate_policy
*a
,
32 const struct lttng_rate_policy
*b
);
33 typedef ssize_t (*rate_policy_create_from_payload_cb
)(
34 struct lttng_payload_view
*view
,
35 struct lttng_rate_policy
**rate_policy
);
36 typedef struct lttng_rate_policy
*(*rate_policy_copy_cb
)(
37 const struct lttng_rate_policy
*source
);
39 struct lttng_rate_policy
{
40 enum lttng_rate_policy_type type
;
41 rate_policy_serialize_cb serialize
;
42 rate_policy_equal_cb equal
;
43 rate_policy_destroy_cb destroy
;
44 rate_policy_copy_cb copy
;
47 struct lttng_rate_policy_every_n
{
48 struct lttng_rate_policy parent
;
52 struct lttng_rate_policy_once_after_n
{
53 struct lttng_rate_policy parent
;
57 struct lttng_rate_policy_comm
{
58 /* enum lttng_rate_policy_type */
59 int8_t rate_policy_type
;
62 struct lttng_rate_policy_once_after_n_comm
{
66 struct lttng_rate_policy_every_n_comm
{
70 /* Forward declaration. */
71 static void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
72 enum lttng_rate_policy_type type
,
73 rate_policy_serialize_cb serialize
,
74 rate_policy_equal_cb equal
,
75 rate_policy_destroy_cb destroy
,
76 rate_policy_copy_cb copy
);
78 /* Forward declaration. Every n */
79 static bool lttng_rate_policy_every_n_should_execute(
80 const struct lttng_rate_policy
*policy
, uint64_t counter
);
82 /* Forward declaration. Once after N */
83 static bool lttng_rate_policy_once_after_n_should_execute(
84 const struct lttng_rate_policy
*policy
, uint64_t counter
);
87 const char *lttng_rate_policy_type_string(
88 enum lttng_rate_policy_type rate_policy_type
)
90 switch (rate_policy_type
) {
91 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
93 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
94 return "ONCE-AFTER-N";
100 enum lttng_rate_policy_type
lttng_rate_policy_get_type(
101 const struct lttng_rate_policy
*policy
)
103 return policy
? policy
->type
: LTTNG_RATE_POLICY_TYPE_UNKNOWN
;
107 void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
108 enum lttng_rate_policy_type type
,
109 rate_policy_serialize_cb serialize
,
110 rate_policy_equal_cb equal
,
111 rate_policy_destroy_cb destroy
,
112 rate_policy_copy_cb copy
)
114 rate_policy
->type
= type
;
115 rate_policy
->serialize
= serialize
;
116 rate_policy
->equal
= equal
;
117 rate_policy
->destroy
= destroy
;
118 rate_policy
->copy
= copy
;
121 void lttng_rate_policy_destroy(struct lttng_rate_policy
*rate_policy
)
127 rate_policy
->destroy(rate_policy
);
131 int lttng_rate_policy_serialize(struct lttng_rate_policy
*rate_policy
,
132 struct lttng_payload
*payload
)
135 struct lttng_rate_policy_comm rate_policy_comm
= {
136 .rate_policy_type
= (int8_t) rate_policy
->type
,
139 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &rate_policy_comm
,
140 sizeof(rate_policy_comm
));
145 ret
= rate_policy
->serialize(rate_policy
, payload
);
153 static ssize_t
lttng_rate_policy_once_after_n_create_from_payload(
154 struct lttng_payload_view
*view
,
155 struct lttng_rate_policy
**rate_policy
)
157 ssize_t consumed_len
= -1;
158 struct lttng_rate_policy
*policy
= NULL
;
159 const struct lttng_rate_policy_once_after_n_comm
*comm
;
160 const struct lttng_payload_view comm_view
=
161 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
163 if (!view
|| !rate_policy
) {
168 if (!lttng_payload_view_is_valid(&comm_view
)) {
169 /* Payload not large enough to contain the header. */
174 comm
= (const struct lttng_rate_policy_once_after_n_comm
*)
175 comm_view
.buffer
.data
;
177 policy
= lttng_rate_policy_once_after_n_create(comm
->threshold
);
178 if (policy
== NULL
) {
183 *rate_policy
= policy
;
184 consumed_len
= sizeof(*comm
);
190 static ssize_t
lttng_rate_policy_every_n_create_from_payload(
191 struct lttng_payload_view
*view
,
192 struct lttng_rate_policy
**rate_policy
)
194 ssize_t consumed_len
= -1;
195 struct lttng_rate_policy
*policy
= NULL
;
196 const struct lttng_rate_policy_every_n_comm
*comm
;
197 const struct lttng_payload_view comm_view
=
198 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
200 if (!view
|| !rate_policy
) {
205 if (!lttng_payload_view_is_valid(&comm_view
)) {
206 /* Payload not large enough to contain the header. */
211 comm
= (const struct lttng_rate_policy_every_n_comm
*)
212 comm_view
.buffer
.data
;
214 policy
= lttng_rate_policy_every_n_create(comm
->interval
);
215 if (policy
== NULL
) {
220 *rate_policy
= policy
;
221 consumed_len
= sizeof(*comm
);
228 ssize_t
lttng_rate_policy_create_from_payload(struct lttng_payload_view
*view
,
229 struct lttng_rate_policy
**rate_policy
)
231 ssize_t consumed_len
, specific_rate_policy_consumed_len
;
232 rate_policy_create_from_payload_cb create_from_payload_cb
;
233 const struct lttng_rate_policy_comm
*rate_policy_comm
;
234 const struct lttng_payload_view rate_policy_comm_view
=
235 lttng_payload_view_from_view(
236 view
, 0, sizeof(*rate_policy_comm
));
238 if (!view
|| !rate_policy
) {
243 if (!lttng_payload_view_is_valid(&rate_policy_comm_view
)) {
244 /* Payload not large enough to contain the header. */
249 rate_policy_comm
= (const struct lttng_rate_policy_comm
*)
250 rate_policy_comm_view
.buffer
.data
;
252 DBG("Create rate_policy from payload: rate-policy-type=%s",
253 lttng_rate_policy_type_string(
254 rate_policy_comm
->rate_policy_type
));
256 switch (rate_policy_comm
->rate_policy_type
) {
257 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
258 create_from_payload_cb
=
259 lttng_rate_policy_every_n_create_from_payload
;
261 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
262 create_from_payload_cb
=
263 lttng_rate_policy_once_after_n_create_from_payload
;
266 ERR("Failed to create rate-policy from payload, unhandled rate-policy type: rate-policy-type=%u (%s)",
267 rate_policy_comm
->rate_policy_type
,
268 lttng_rate_policy_type_string(
269 rate_policy_comm
->rate_policy_type
));
275 /* Create buffer view for the rate_policy-type-specific data.
277 struct lttng_payload_view specific_rate_policy_view
=
278 lttng_payload_view_from_view(view
,
279 sizeof(struct lttng_rate_policy_comm
),
282 specific_rate_policy_consumed_len
= create_from_payload_cb(
283 &specific_rate_policy_view
, rate_policy
);
285 if (specific_rate_policy_consumed_len
< 0) {
286 ERR("Failed to create specific rate_policy from buffer.");
291 assert(*rate_policy
);
293 consumed_len
= sizeof(struct lttng_rate_policy_comm
) +
294 specific_rate_policy_consumed_len
;
301 bool lttng_rate_policy_is_equal(const struct lttng_rate_policy
*a
,
302 const struct lttng_rate_policy
*b
)
304 bool is_equal
= false;
310 if (a
->type
!= b
->type
) {
320 is_equal
= a
->equal(a
, b
);
326 bool lttng_rate_policy_should_execute(
327 const struct lttng_rate_policy
*policy
, uint64_t counter
)
329 switch (policy
->type
) {
330 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
331 return lttng_rate_policy_every_n_should_execute(
333 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
334 return lttng_rate_policy_once_after_n_should_execute(
343 static struct lttng_rate_policy_every_n
*rate_policy_every_n_from_rate_policy(
344 struct lttng_rate_policy
*policy
)
348 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
351 static const struct lttng_rate_policy_every_n
*
352 rate_policy_every_n_from_rate_policy_const(
353 const struct lttng_rate_policy
*policy
)
357 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
360 static int lttng_rate_policy_every_n_serialize(
361 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
365 struct lttng_rate_policy_every_n
*every_n_policy
;
366 struct lttng_rate_policy_every_n_comm comm
= {};
371 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
372 comm
.interval
= every_n_policy
->interval
;
374 ret
= lttng_dynamic_buffer_append(
375 &payload
->buffer
, &comm
, sizeof(comm
));
379 static bool lttng_rate_policy_every_n_is_equal(
380 const struct lttng_rate_policy
*_a
,
381 const struct lttng_rate_policy
*_b
)
383 bool is_equal
= false;
384 const struct lttng_rate_policy_every_n
*a
, *b
;
386 a
= rate_policy_every_n_from_rate_policy_const(_a
);
387 b
= rate_policy_every_n_from_rate_policy_const(_b
);
389 if (a
->interval
!= b
->interval
) {
399 static void lttng_rate_policy_every_n_destroy(struct lttng_rate_policy
*policy
)
401 struct lttng_rate_policy_every_n
*every_n_policy
;
407 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
409 free(every_n_policy
);
415 static struct lttng_rate_policy
*lttng_rate_policy_every_n_copy(
416 const struct lttng_rate_policy
*source
)
418 struct lttng_rate_policy
*copy
= NULL
;
419 const struct lttng_rate_policy_every_n
*every_n_policy
;
425 every_n_policy
= rate_policy_every_n_from_rate_policy_const(source
);
426 copy
= lttng_rate_policy_every_n_create(every_n_policy
->interval
);
432 struct lttng_rate_policy
*lttng_rate_policy_every_n_create(uint64_t interval
)
434 struct lttng_rate_policy_every_n
*policy
= NULL
;
435 struct lttng_rate_policy
*_policy
= NULL
;
439 * An interval of 0 is invalid since it would never be fired.
444 policy
= zmalloc(sizeof(struct lttng_rate_policy_every_n
));
449 lttng_rate_policy_init(&policy
->parent
, LTTNG_RATE_POLICY_TYPE_EVERY_N
,
450 lttng_rate_policy_every_n_serialize
,
451 lttng_rate_policy_every_n_is_equal
,
452 lttng_rate_policy_every_n_destroy
,
453 lttng_rate_policy_every_n_copy
);
455 policy
->interval
= interval
;
457 _policy
= &policy
->parent
;
466 enum lttng_rate_policy_status
lttng_rate_policy_every_n_get_interval(
467 const struct lttng_rate_policy
*policy
, uint64_t *interval
)
469 const struct lttng_rate_policy_every_n
*every_n_policy
;
470 enum lttng_rate_policy_status status
;
472 if (!policy
|| !IS_EVERY_N_RATE_POLICY(policy
) || !interval
) {
473 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
477 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
478 *interval
= every_n_policy
->interval
;
479 status
= LTTNG_RATE_POLICY_STATUS_OK
;
485 static bool lttng_rate_policy_every_n_should_execute(
486 const struct lttng_rate_policy
*policy
, uint64_t counter
)
488 const struct lttng_rate_policy_every_n
*every_n_policy
;
490 bool execute
= false;
492 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
494 if (every_n_policy
->interval
== 0) {
498 execute
= (counter
% every_n_policy
->interval
) == 0;
500 DBG("Policy every N = %" PRIu64
501 ": execution %s. Execution count: %" PRIu64
,
502 every_n_policy
->interval
,
503 execute
? "accepted" : "denied", counter
);
510 static struct lttng_rate_policy_once_after_n
*
511 rate_policy_once_after_n_from_rate_policy(struct lttng_rate_policy
*policy
)
516 policy
, struct lttng_rate_policy_once_after_n
, parent
);
519 static const struct lttng_rate_policy_once_after_n
*
520 rate_policy_once_after_n_from_rate_policy_const(
521 const struct lttng_rate_policy
*policy
)
526 policy
, struct lttng_rate_policy_once_after_n
, parent
);
528 static int lttng_rate_policy_once_after_n_serialize(
529 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
533 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
534 struct lttng_rate_policy_once_after_n_comm comm
= {};
539 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
540 comm
.threshold
= once_after_n_policy
->threshold
;
542 ret
= lttng_dynamic_buffer_append(
543 &payload
->buffer
, &comm
, sizeof(comm
));
547 static bool lttng_rate_policy_once_after_n_is_equal(
548 const struct lttng_rate_policy
*_a
,
549 const struct lttng_rate_policy
*_b
)
551 bool is_equal
= false;
552 const struct lttng_rate_policy_once_after_n
*a
, *b
;
554 a
= rate_policy_once_after_n_from_rate_policy_const(_a
);
555 b
= rate_policy_once_after_n_from_rate_policy_const(_b
);
557 if (a
->threshold
!= b
->threshold
) {
567 static void lttng_rate_policy_once_after_n_destroy(
568 struct lttng_rate_policy
*policy
)
570 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
576 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
578 free(once_after_n_policy
);
584 static struct lttng_rate_policy
*lttng_rate_policy_once_after_n_copy(
585 const struct lttng_rate_policy
*source
)
587 struct lttng_rate_policy
*copy
= NULL
;
588 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
594 once_after_n_policy
=
595 rate_policy_once_after_n_from_rate_policy_const(source
);
596 copy
= lttng_rate_policy_once_after_n_create(
597 once_after_n_policy
->threshold
);
603 struct lttng_rate_policy
*lttng_rate_policy_once_after_n_create(
606 struct lttng_rate_policy_once_after_n
*policy
= NULL
;
607 struct lttng_rate_policy
*_policy
= NULL
;
609 if (threshold
== 0) {
610 /* threshold is expected to be > 0 */
614 policy
= zmalloc(sizeof(struct lttng_rate_policy_once_after_n
));
619 lttng_rate_policy_init(&policy
->parent
,
620 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
,
621 lttng_rate_policy_once_after_n_serialize
,
622 lttng_rate_policy_once_after_n_is_equal
,
623 lttng_rate_policy_once_after_n_destroy
,
624 lttng_rate_policy_once_after_n_copy
);
626 policy
->threshold
= threshold
;
628 _policy
= &policy
->parent
;
637 enum lttng_rate_policy_status
lttng_rate_policy_once_after_n_get_threshold(
638 const struct lttng_rate_policy
*policy
, uint64_t *threshold
)
640 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
641 enum lttng_rate_policy_status status
;
643 if (!policy
|| !IS_ONCE_AFTER_N_RATE_POLICY(policy
) || !threshold
) {
644 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
648 once_after_n_policy
=
649 rate_policy_once_after_n_from_rate_policy_const(policy
);
650 *threshold
= once_after_n_policy
->threshold
;
651 status
= LTTNG_RATE_POLICY_STATUS_OK
;
658 struct lttng_rate_policy
*lttng_rate_policy_copy(
659 const struct lttng_rate_policy
*source
)
661 assert(source
->copy
);
662 return source
->copy(source
);
665 static bool lttng_rate_policy_once_after_n_should_execute(
666 const struct lttng_rate_policy
*policy
, uint64_t counter
)
668 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
669 bool execute
= false;
672 once_after_n_policy
=
673 rate_policy_once_after_n_from_rate_policy_const(policy
);
675 execute
= counter
== once_after_n_policy
->threshold
;
677 DBG("Policy once after N = %" PRIu64
678 ": execution %s. Execution count: %" PRIu64
,
679 once_after_n_policy
->threshold
,
680 execute
? "accepted" : "denied", counter
);
682 return counter
== once_after_n_policy
->threshold
;