2 * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/buffer-view.hpp>
9 #include <common/dynamic-buffer.hpp>
10 #include <common/error.hpp>
11 #include <common/macros.hpp>
12 #include <common/mi-lttng.hpp>
13 #include <common/payload-view.hpp>
14 #include <common/payload.hpp>
16 #include <lttng/action/rate-policy-internal.hpp>
17 #include <lttng/action/rate-policy.h>
21 #include <sys/types.h>
23 #define IS_EVERY_N_RATE_POLICY(policy) \
24 (lttng_rate_policy_get_type(policy) == LTTNG_RATE_POLICY_TYPE_EVERY_N)
26 #define IS_ONCE_AFTER_N_RATE_POLICY(policy) \
27 (lttng_rate_policy_get_type(policy) == LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N)
29 using rate_policy_destroy_cb
= void (*)(struct lttng_rate_policy
*);
30 using rate_policy_serialize_cb
= int (*)(struct lttng_rate_policy
*, struct lttng_payload
*);
31 using rate_policy_equal_cb
= bool (*)(const struct lttng_rate_policy
*,
32 const struct lttng_rate_policy
*);
33 using rate_policy_create_from_payload_cb
= ssize_t (*)(struct lttng_payload_view
*,
34 struct lttng_rate_policy
**);
35 using rate_policy_copy_cb
= struct lttng_rate_policy
*(*) (const struct lttng_rate_policy
*);
36 using rate_policy_mi_serialize_cb
= enum lttng_error_code (*)(const struct lttng_rate_policy
*,
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
;
45 rate_policy_mi_serialize_cb mi_serialize
;
49 struct lttng_rate_policy_every_n
{
50 struct lttng_rate_policy parent
;
54 struct lttng_rate_policy_once_after_n
{
55 struct lttng_rate_policy parent
;
59 struct lttng_rate_policy_comm
{
60 /* enum lttng_rate_policy_type */
61 int8_t rate_policy_type
;
64 struct lttng_rate_policy_once_after_n_comm
{
68 struct lttng_rate_policy_every_n_comm
{
73 /* Forward declaration. */
74 static void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
75 enum lttng_rate_policy_type type
,
76 rate_policy_serialize_cb serialize
,
77 rate_policy_equal_cb equal
,
78 rate_policy_destroy_cb destroy
,
79 rate_policy_copy_cb copy
,
80 rate_policy_mi_serialize_cb mi
);
82 /* Forward declaration. Every n */
83 static bool lttng_rate_policy_every_n_should_execute(const struct lttng_rate_policy
*policy
,
86 /* Forward declaration. Once after N */
87 static bool lttng_rate_policy_once_after_n_should_execute(const struct lttng_rate_policy
*policy
,
90 const char *lttng_rate_policy_type_string(enum lttng_rate_policy_type rate_policy_type
)
92 switch (rate_policy_type
) {
93 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
95 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
96 return "ONCE-AFTER-N";
102 enum lttng_rate_policy_type
lttng_rate_policy_get_type(const struct lttng_rate_policy
*policy
)
104 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
,
113 rate_policy_mi_serialize_cb mi
)
115 rate_policy
->type
= type
;
116 rate_policy
->serialize
= serialize
;
117 rate_policy
->equal
= equal
;
118 rate_policy
->destroy
= destroy
;
119 rate_policy
->copy
= copy
;
120 rate_policy
->mi_serialize
= mi
;
123 void lttng_rate_policy_destroy(struct lttng_rate_policy
*rate_policy
)
129 rate_policy
->destroy(rate_policy
);
132 int lttng_rate_policy_serialize(struct lttng_rate_policy
*rate_policy
,
133 struct lttng_payload
*payload
)
136 struct lttng_rate_policy_comm rate_policy_comm
= {
137 .rate_policy_type
= (int8_t) rate_policy
->type
,
140 ret
= lttng_dynamic_buffer_append(
141 &payload
->buffer
, &rate_policy_comm
, sizeof(rate_policy_comm
));
146 ret
= rate_policy
->serialize(rate_policy
, payload
);
155 lttng_rate_policy_once_after_n_create_from_payload(struct lttng_payload_view
*view
,
156 struct lttng_rate_policy
**rate_policy
)
158 ssize_t consumed_len
= -1;
159 struct lttng_rate_policy
*policy
= nullptr;
160 const struct lttng_rate_policy_once_after_n_comm
*comm
;
161 const struct lttng_payload_view comm_view
=
162 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
164 if (!view
|| !rate_policy
) {
169 if (!lttng_payload_view_is_valid(&comm_view
)) {
170 /* Payload not large enough to contain the header. */
175 comm
= (const struct lttng_rate_policy_once_after_n_comm
*) comm_view
.buffer
.data
;
177 policy
= lttng_rate_policy_once_after_n_create(comm
->threshold
);
178 if (policy
== nullptr) {
183 *rate_policy
= policy
;
184 consumed_len
= sizeof(*comm
);
190 static ssize_t
lttng_rate_policy_every_n_create_from_payload(struct lttng_payload_view
*view
,
191 struct lttng_rate_policy
**rate_policy
)
193 ssize_t consumed_len
= -1;
194 struct lttng_rate_policy
*policy
= nullptr;
195 const struct lttng_rate_policy_every_n_comm
*comm
;
196 const struct lttng_payload_view comm_view
=
197 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
199 if (!view
|| !rate_policy
) {
204 if (!lttng_payload_view_is_valid(&comm_view
)) {
205 /* Payload not large enough to contain the header. */
210 comm
= (const struct lttng_rate_policy_every_n_comm
*) comm_view
.buffer
.data
;
212 policy
= lttng_rate_policy_every_n_create(comm
->interval
);
213 if (policy
== nullptr) {
218 *rate_policy
= policy
;
219 consumed_len
= sizeof(*comm
);
225 ssize_t
lttng_rate_policy_create_from_payload(struct lttng_payload_view
*view
,
226 struct lttng_rate_policy
**rate_policy
)
228 ssize_t consumed_len
, specific_rate_policy_consumed_len
;
229 rate_policy_create_from_payload_cb create_from_payload_cb
;
230 const struct lttng_rate_policy_comm
*rate_policy_comm
;
231 const struct lttng_payload_view rate_policy_comm_view
=
232 lttng_payload_view_from_view(view
, 0, sizeof(*rate_policy_comm
));
234 if (!view
|| !rate_policy
) {
239 if (!lttng_payload_view_is_valid(&rate_policy_comm_view
)) {
240 /* Payload not large enough to contain the header. */
246 (const struct lttng_rate_policy_comm
*) rate_policy_comm_view
.buffer
.data
;
248 DBG("Create rate_policy from payload: rate-policy-type=%s",
249 lttng_rate_policy_type_string(
250 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
252 switch (rate_policy_comm
->rate_policy_type
) {
253 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
254 create_from_payload_cb
= lttng_rate_policy_every_n_create_from_payload
;
256 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
257 create_from_payload_cb
= lttng_rate_policy_once_after_n_create_from_payload
;
260 ERR("Failed to create rate-policy from payload, unhandled rate-policy type: rate-policy-type=%u (%s)",
261 rate_policy_comm
->rate_policy_type
,
262 lttng_rate_policy_type_string(
263 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
269 /* Create buffer view for the rate_policy-type-specific data.
271 struct lttng_payload_view specific_rate_policy_view
= lttng_payload_view_from_view(
272 view
, sizeof(struct lttng_rate_policy_comm
), -1);
274 specific_rate_policy_consumed_len
=
275 create_from_payload_cb(&specific_rate_policy_view
, rate_policy
);
277 if (specific_rate_policy_consumed_len
< 0) {
278 ERR("Failed to create specific rate_policy from buffer.");
283 LTTNG_ASSERT(*rate_policy
);
285 consumed_len
= sizeof(struct lttng_rate_policy_comm
) + specific_rate_policy_consumed_len
;
291 bool lttng_rate_policy_is_equal(const struct lttng_rate_policy
*a
,
292 const struct lttng_rate_policy
*b
)
294 bool is_equal
= false;
300 if (a
->type
!= b
->type
) {
309 LTTNG_ASSERT(a
->equal
);
310 is_equal
= a
->equal(a
, b
);
315 bool lttng_rate_policy_should_execute(const struct lttng_rate_policy
*policy
, uint64_t counter
)
317 switch (policy
->type
) {
318 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
319 return lttng_rate_policy_every_n_should_execute(policy
, counter
);
320 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
321 return lttng_rate_policy_once_after_n_should_execute(policy
, counter
);
329 static struct lttng_rate_policy_every_n
*
330 rate_policy_every_n_from_rate_policy(struct lttng_rate_policy
*policy
)
332 LTTNG_ASSERT(policy
);
334 return lttng::utils::container_of(policy
, <tng_rate_policy_every_n::parent
);
337 static const struct lttng_rate_policy_every_n
*
338 rate_policy_every_n_from_rate_policy_const(const struct lttng_rate_policy
*policy
)
340 LTTNG_ASSERT(policy
);
342 return lttng::utils::container_of(policy
, <tng_rate_policy_every_n::parent
);
345 static int lttng_rate_policy_every_n_serialize(struct lttng_rate_policy
*policy
,
346 struct lttng_payload
*payload
)
350 struct lttng_rate_policy_every_n
*every_n_policy
;
351 struct lttng_rate_policy_every_n_comm comm
= {};
353 LTTNG_ASSERT(policy
);
354 LTTNG_ASSERT(payload
);
356 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
357 comm
.interval
= every_n_policy
->interval
;
359 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &comm
, sizeof(comm
));
363 static bool lttng_rate_policy_every_n_is_equal(const struct lttng_rate_policy
*_a
,
364 const struct lttng_rate_policy
*_b
)
366 bool is_equal
= false;
367 const struct lttng_rate_policy_every_n
*a
, *b
;
369 a
= rate_policy_every_n_from_rate_policy_const(_a
);
370 b
= rate_policy_every_n_from_rate_policy_const(_b
);
372 if (a
->interval
!= b
->interval
) {
382 static void lttng_rate_policy_every_n_destroy(struct lttng_rate_policy
*policy
)
384 struct lttng_rate_policy_every_n
*every_n_policy
;
390 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
392 free(every_n_policy
);
398 static struct lttng_rate_policy
*
399 lttng_rate_policy_every_n_copy(const struct lttng_rate_policy
*source
)
401 struct lttng_rate_policy
*copy
= nullptr;
402 const struct lttng_rate_policy_every_n
*every_n_policy
;
408 every_n_policy
= rate_policy_every_n_from_rate_policy_const(source
);
409 copy
= lttng_rate_policy_every_n_create(every_n_policy
->interval
);
415 static enum lttng_error_code
416 lttng_rate_policy_every_n_mi_serialize(const struct lttng_rate_policy
*rate_policy
,
417 struct mi_writer
*writer
)
420 enum lttng_error_code ret_code
;
421 const struct lttng_rate_policy_every_n
*every_n_policy
= nullptr;
423 LTTNG_ASSERT(rate_policy
);
424 LTTNG_ASSERT(IS_EVERY_N_RATE_POLICY(rate_policy
));
425 LTTNG_ASSERT(writer
);
427 every_n_policy
= rate_policy_every_n_from_rate_policy_const(rate_policy
);
429 /* Open rate_policy_every_n element. */
430 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_rate_policy_every_n
);
436 ret
= mi_lttng_writer_write_element_unsigned_int(
437 writer
, mi_lttng_element_rate_policy_every_n_interval
, every_n_policy
->interval
);
442 /* Close rate_policy_every_n element. */
443 ret
= mi_lttng_writer_close_element(writer
);
452 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
457 struct lttng_rate_policy
*lttng_rate_policy_every_n_create(uint64_t interval
)
459 struct lttng_rate_policy_every_n
*policy
= nullptr;
460 struct lttng_rate_policy
*_policy
= nullptr;
464 * An interval of 0 is invalid since it would never be fired.
469 policy
= zmalloc
<lttng_rate_policy_every_n
>();
474 lttng_rate_policy_init(&policy
->parent
,
475 LTTNG_RATE_POLICY_TYPE_EVERY_N
,
476 lttng_rate_policy_every_n_serialize
,
477 lttng_rate_policy_every_n_is_equal
,
478 lttng_rate_policy_every_n_destroy
,
479 lttng_rate_policy_every_n_copy
,
480 lttng_rate_policy_every_n_mi_serialize
);
482 policy
->interval
= interval
;
484 _policy
= &policy
->parent
;
492 enum lttng_rate_policy_status
493 lttng_rate_policy_every_n_get_interval(const struct lttng_rate_policy
*policy
, uint64_t *interval
)
495 const struct lttng_rate_policy_every_n
*every_n_policy
;
496 enum lttng_rate_policy_status status
;
498 if (!policy
|| !IS_EVERY_N_RATE_POLICY(policy
) || !interval
) {
499 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
503 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
504 *interval
= every_n_policy
->interval
;
505 status
= LTTNG_RATE_POLICY_STATUS_OK
;
511 static bool lttng_rate_policy_every_n_should_execute(const struct lttng_rate_policy
*policy
,
514 const struct lttng_rate_policy_every_n
*every_n_policy
;
515 LTTNG_ASSERT(policy
);
516 bool execute
= false;
518 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
520 if (every_n_policy
->interval
== 0) {
524 execute
= (counter
% every_n_policy
->interval
) == 0;
526 DBG("Policy every N = %" PRIu64
": execution %s. Execution count: %" PRIu64
,
527 every_n_policy
->interval
,
528 execute
? "accepted" : "denied",
536 static struct lttng_rate_policy_once_after_n
*
537 rate_policy_once_after_n_from_rate_policy(struct lttng_rate_policy
*policy
)
539 LTTNG_ASSERT(policy
);
541 return lttng::utils::container_of(policy
, <tng_rate_policy_once_after_n::parent
);
544 static const struct lttng_rate_policy_once_after_n
*
545 rate_policy_once_after_n_from_rate_policy_const(const struct lttng_rate_policy
*policy
)
547 LTTNG_ASSERT(policy
);
549 return lttng::utils::container_of(policy
, <tng_rate_policy_once_after_n::parent
);
551 static int lttng_rate_policy_once_after_n_serialize(struct lttng_rate_policy
*policy
,
552 struct lttng_payload
*payload
)
556 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
557 struct lttng_rate_policy_once_after_n_comm comm
= {};
559 LTTNG_ASSERT(policy
);
560 LTTNG_ASSERT(payload
);
562 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
563 comm
.threshold
= once_after_n_policy
->threshold
;
565 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &comm
, sizeof(comm
));
569 static bool lttng_rate_policy_once_after_n_is_equal(const struct lttng_rate_policy
*_a
,
570 const struct lttng_rate_policy
*_b
)
572 bool is_equal
= false;
573 const struct lttng_rate_policy_once_after_n
*a
, *b
;
575 a
= rate_policy_once_after_n_from_rate_policy_const(_a
);
576 b
= rate_policy_once_after_n_from_rate_policy_const(_b
);
578 if (a
->threshold
!= b
->threshold
) {
588 static void lttng_rate_policy_once_after_n_destroy(struct lttng_rate_policy
*policy
)
590 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
596 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
598 free(once_after_n_policy
);
604 static struct lttng_rate_policy
*
605 lttng_rate_policy_once_after_n_copy(const struct lttng_rate_policy
*source
)
607 struct lttng_rate_policy
*copy
= nullptr;
608 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
614 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(source
);
615 copy
= lttng_rate_policy_once_after_n_create(once_after_n_policy
->threshold
);
621 static enum lttng_error_code
622 lttng_rate_policy_once_after_n_mi_serialize(const struct lttng_rate_policy
*rate_policy
,
623 struct mi_writer
*writer
)
626 enum lttng_error_code ret_code
;
627 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
= nullptr;
629 LTTNG_ASSERT(rate_policy
);
630 LTTNG_ASSERT(IS_ONCE_AFTER_N_RATE_POLICY(rate_policy
));
631 LTTNG_ASSERT(writer
);
633 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(rate_policy
);
635 /* Open rate_policy_once_after_n. */
636 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_rate_policy_once_after_n
);
642 ret
= mi_lttng_writer_write_element_unsigned_int(
644 mi_lttng_element_rate_policy_once_after_n_threshold
,
645 once_after_n_policy
->threshold
);
650 /* Close rate_policy_once_after_n element. */
651 ret
= mi_lttng_writer_close_element(writer
);
660 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
665 struct lttng_rate_policy
*lttng_rate_policy_once_after_n_create(uint64_t threshold
)
667 struct lttng_rate_policy_once_after_n
*policy
= nullptr;
668 struct lttng_rate_policy
*_policy
= nullptr;
670 if (threshold
== 0) {
671 /* threshold is expected to be > 0 */
675 policy
= zmalloc
<lttng_rate_policy_once_after_n
>();
680 lttng_rate_policy_init(&policy
->parent
,
681 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
,
682 lttng_rate_policy_once_after_n_serialize
,
683 lttng_rate_policy_once_after_n_is_equal
,
684 lttng_rate_policy_once_after_n_destroy
,
685 lttng_rate_policy_once_after_n_copy
,
686 lttng_rate_policy_once_after_n_mi_serialize
);
688 policy
->threshold
= threshold
;
690 _policy
= &policy
->parent
;
698 enum lttng_rate_policy_status
699 lttng_rate_policy_once_after_n_get_threshold(const struct lttng_rate_policy
*policy
,
702 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
703 enum lttng_rate_policy_status status
;
705 if (!policy
|| !IS_ONCE_AFTER_N_RATE_POLICY(policy
) || !threshold
) {
706 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
710 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(policy
);
711 *threshold
= once_after_n_policy
->threshold
;
712 status
= LTTNG_RATE_POLICY_STATUS_OK
;
718 struct lttng_rate_policy
*lttng_rate_policy_copy(const struct lttng_rate_policy
*source
)
720 LTTNG_ASSERT(source
->copy
);
721 return source
->copy(source
);
724 static bool lttng_rate_policy_once_after_n_should_execute(const struct lttng_rate_policy
*policy
,
727 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
728 bool execute
= false;
729 LTTNG_ASSERT(policy
);
731 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(policy
);
733 execute
= counter
== once_after_n_policy
->threshold
;
735 DBG("Policy once after N = %" PRIu64
": execution %s. Execution count: %" PRIu64
,
736 once_after_n_policy
->threshold
,
737 execute
? "accepted" : "denied",
740 return counter
== once_after_n_policy
->threshold
;
743 enum lttng_error_code
lttng_rate_policy_mi_serialize(const struct lttng_rate_policy
*rate_policy
,
744 struct mi_writer
*writer
)
747 enum lttng_error_code ret_code
;
749 LTTNG_ASSERT(rate_policy
);
750 LTTNG_ASSERT(writer
);
751 LTTNG_ASSERT(rate_policy
->mi_serialize
);
753 /* Open rate policy element. */
754 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_rate_policy
);
759 /* Serialize underlying rate policy. */
760 ret_code
= rate_policy
->mi_serialize(rate_policy
, writer
);
761 if (ret_code
!= LTTNG_OK
) {
765 /* Close rate policy element. */
766 ret
= mi_lttng_writer_close_element(writer
);
775 ret_code
= LTTNG_ERR_MI_IO_FAIL
;