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 typedef void (*rate_policy_destroy_cb
)(struct lttng_rate_policy
*rate_policy
);
30 typedef int (*rate_policy_serialize_cb
)(struct lttng_rate_policy
*rate_policy
,
31 struct lttng_payload
*payload
);
32 typedef bool (*rate_policy_equal_cb
)(const struct lttng_rate_policy
*a
,
33 const struct lttng_rate_policy
*b
);
34 typedef ssize_t (*rate_policy_create_from_payload_cb
)(struct lttng_payload_view
*view
,
35 struct lttng_rate_policy
**rate_policy
);
36 typedef struct lttng_rate_policy
*(*rate_policy_copy_cb
)(const struct lttng_rate_policy
*source
);
37 typedef enum lttng_error_code (*rate_policy_mi_serialize_cb
)(
38 const struct lttng_rate_policy
*rate_policy
, struct mi_writer
*writer
);
40 struct lttng_rate_policy
{
41 enum lttng_rate_policy_type type
;
42 rate_policy_serialize_cb serialize
;
43 rate_policy_equal_cb equal
;
44 rate_policy_destroy_cb destroy
;
45 rate_policy_copy_cb copy
;
46 rate_policy_mi_serialize_cb mi_serialize
;
50 struct lttng_rate_policy_every_n
{
51 struct lttng_rate_policy parent
;
55 struct lttng_rate_policy_once_after_n
{
56 struct lttng_rate_policy parent
;
60 struct lttng_rate_policy_comm
{
61 /* enum lttng_rate_policy_type */
62 int8_t rate_policy_type
;
65 struct lttng_rate_policy_once_after_n_comm
{
69 struct lttng_rate_policy_every_n_comm
{
74 /* Forward declaration. */
75 static void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
76 enum lttng_rate_policy_type type
,
77 rate_policy_serialize_cb serialize
,
78 rate_policy_equal_cb equal
,
79 rate_policy_destroy_cb destroy
,
80 rate_policy_copy_cb copy
,
81 rate_policy_mi_serialize_cb mi
);
83 /* Forward declaration. Every n */
84 static bool lttng_rate_policy_every_n_should_execute(const struct lttng_rate_policy
*policy
,
87 /* Forward declaration. Once after N */
88 static bool lttng_rate_policy_once_after_n_should_execute(const struct lttng_rate_policy
*policy
,
91 const char *lttng_rate_policy_type_string(enum lttng_rate_policy_type rate_policy_type
)
93 switch (rate_policy_type
) {
94 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
96 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
97 return "ONCE-AFTER-N";
103 enum lttng_rate_policy_type
lttng_rate_policy_get_type(const struct lttng_rate_policy
*policy
)
105 return policy
? policy
->type
: LTTNG_RATE_POLICY_TYPE_UNKNOWN
;
108 void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
109 enum lttng_rate_policy_type type
,
110 rate_policy_serialize_cb serialize
,
111 rate_policy_equal_cb equal
,
112 rate_policy_destroy_cb destroy
,
113 rate_policy_copy_cb copy
,
114 rate_policy_mi_serialize_cb mi
)
116 rate_policy
->type
= type
;
117 rate_policy
->serialize
= serialize
;
118 rate_policy
->equal
= equal
;
119 rate_policy
->destroy
= destroy
;
120 rate_policy
->copy
= copy
;
121 rate_policy
->mi_serialize
= mi
;
124 void lttng_rate_policy_destroy(struct lttng_rate_policy
*rate_policy
)
130 rate_policy
->destroy(rate_policy
);
133 int lttng_rate_policy_serialize(struct lttng_rate_policy
*rate_policy
,
134 struct lttng_payload
*payload
)
137 struct lttng_rate_policy_comm rate_policy_comm
= {
138 .rate_policy_type
= (int8_t) rate_policy
->type
,
141 ret
= lttng_dynamic_buffer_append(
142 &payload
->buffer
, &rate_policy_comm
, sizeof(rate_policy_comm
));
147 ret
= rate_policy
->serialize(rate_policy
, payload
);
156 lttng_rate_policy_once_after_n_create_from_payload(struct lttng_payload_view
*view
,
157 struct lttng_rate_policy
**rate_policy
)
159 ssize_t consumed_len
= -1;
160 struct lttng_rate_policy
*policy
= NULL
;
161 const struct lttng_rate_policy_once_after_n_comm
*comm
;
162 const struct lttng_payload_view comm_view
=
163 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
165 if (!view
|| !rate_policy
) {
170 if (!lttng_payload_view_is_valid(&comm_view
)) {
171 /* Payload not large enough to contain the header. */
176 comm
= (const struct lttng_rate_policy_once_after_n_comm
*) comm_view
.buffer
.data
;
178 policy
= lttng_rate_policy_once_after_n_create(comm
->threshold
);
179 if (policy
== NULL
) {
184 *rate_policy
= policy
;
185 consumed_len
= sizeof(*comm
);
191 static ssize_t
lttng_rate_policy_every_n_create_from_payload(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
*) comm_view
.buffer
.data
;
213 policy
= lttng_rate_policy_every_n_create(comm
->interval
);
214 if (policy
== NULL
) {
219 *rate_policy
= policy
;
220 consumed_len
= sizeof(*comm
);
226 ssize_t
lttng_rate_policy_create_from_payload(struct lttng_payload_view
*view
,
227 struct lttng_rate_policy
**rate_policy
)
229 ssize_t consumed_len
, specific_rate_policy_consumed_len
;
230 rate_policy_create_from_payload_cb create_from_payload_cb
;
231 const struct lttng_rate_policy_comm
*rate_policy_comm
;
232 const struct lttng_payload_view rate_policy_comm_view
=
233 lttng_payload_view_from_view(view
, 0, sizeof(*rate_policy_comm
));
235 if (!view
|| !rate_policy
) {
240 if (!lttng_payload_view_is_valid(&rate_policy_comm_view
)) {
241 /* Payload not large enough to contain the header. */
247 (const struct lttng_rate_policy_comm
*) rate_policy_comm_view
.buffer
.data
;
249 DBG("Create rate_policy from payload: rate-policy-type=%s",
250 lttng_rate_policy_type_string(
251 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
253 switch (rate_policy_comm
->rate_policy_type
) {
254 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
255 create_from_payload_cb
= lttng_rate_policy_every_n_create_from_payload
;
257 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
258 create_from_payload_cb
= lttng_rate_policy_once_after_n_create_from_payload
;
261 ERR("Failed to create rate-policy from payload, unhandled rate-policy type: rate-policy-type=%u (%s)",
262 rate_policy_comm
->rate_policy_type
,
263 lttng_rate_policy_type_string(
264 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
270 /* Create buffer view for the rate_policy-type-specific data.
272 struct lttng_payload_view specific_rate_policy_view
= lttng_payload_view_from_view(
273 view
, sizeof(struct lttng_rate_policy_comm
), -1);
275 specific_rate_policy_consumed_len
=
276 create_from_payload_cb(&specific_rate_policy_view
, rate_policy
);
278 if (specific_rate_policy_consumed_len
< 0) {
279 ERR("Failed to create specific rate_policy from buffer.");
284 LTTNG_ASSERT(*rate_policy
);
286 consumed_len
= sizeof(struct lttng_rate_policy_comm
) + specific_rate_policy_consumed_len
;
292 bool lttng_rate_policy_is_equal(const struct lttng_rate_policy
*a
,
293 const struct lttng_rate_policy
*b
)
295 bool is_equal
= false;
301 if (a
->type
!= b
->type
) {
310 LTTNG_ASSERT(a
->equal
);
311 is_equal
= a
->equal(a
, b
);
316 bool lttng_rate_policy_should_execute(const struct lttng_rate_policy
*policy
, uint64_t counter
)
318 switch (policy
->type
) {
319 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
320 return lttng_rate_policy_every_n_should_execute(policy
, counter
);
321 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
322 return lttng_rate_policy_once_after_n_should_execute(policy
, counter
);
330 static struct lttng_rate_policy_every_n
*
331 rate_policy_every_n_from_rate_policy(struct lttng_rate_policy
*policy
)
333 LTTNG_ASSERT(policy
);
335 return lttng::utils::container_of(policy
, <tng_rate_policy_every_n::parent
);
338 static const struct lttng_rate_policy_every_n
*
339 rate_policy_every_n_from_rate_policy_const(const struct lttng_rate_policy
*policy
)
341 LTTNG_ASSERT(policy
);
343 return lttng::utils::container_of(policy
, <tng_rate_policy_every_n::parent
);
346 static int lttng_rate_policy_every_n_serialize(struct lttng_rate_policy
*policy
,
347 struct lttng_payload
*payload
)
351 struct lttng_rate_policy_every_n
*every_n_policy
;
352 struct lttng_rate_policy_every_n_comm comm
= {};
354 LTTNG_ASSERT(policy
);
355 LTTNG_ASSERT(payload
);
357 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
358 comm
.interval
= every_n_policy
->interval
;
360 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &comm
, sizeof(comm
));
364 static bool lttng_rate_policy_every_n_is_equal(const struct lttng_rate_policy
*_a
,
365 const struct lttng_rate_policy
*_b
)
367 bool is_equal
= false;
368 const struct lttng_rate_policy_every_n
*a
, *b
;
370 a
= rate_policy_every_n_from_rate_policy_const(_a
);
371 b
= rate_policy_every_n_from_rate_policy_const(_b
);
373 if (a
->interval
!= b
->interval
) {
383 static void lttng_rate_policy_every_n_destroy(struct lttng_rate_policy
*policy
)
385 struct lttng_rate_policy_every_n
*every_n_policy
;
391 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
393 free(every_n_policy
);
399 static struct lttng_rate_policy
*
400 lttng_rate_policy_every_n_copy(const struct lttng_rate_policy
*source
)
402 struct lttng_rate_policy
*copy
= NULL
;
403 const struct lttng_rate_policy_every_n
*every_n_policy
;
409 every_n_policy
= rate_policy_every_n_from_rate_policy_const(source
);
410 copy
= lttng_rate_policy_every_n_create(every_n_policy
->interval
);
416 static enum lttng_error_code
417 lttng_rate_policy_every_n_mi_serialize(const struct lttng_rate_policy
*rate_policy
,
418 struct mi_writer
*writer
)
421 enum lttng_error_code ret_code
;
422 const struct lttng_rate_policy_every_n
*every_n_policy
= NULL
;
424 LTTNG_ASSERT(rate_policy
);
425 LTTNG_ASSERT(IS_EVERY_N_RATE_POLICY(rate_policy
));
426 LTTNG_ASSERT(writer
);
428 every_n_policy
= rate_policy_every_n_from_rate_policy_const(rate_policy
);
430 /* Open rate_policy_every_n element. */
431 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_rate_policy_every_n
);
437 ret
= mi_lttng_writer_write_element_unsigned_int(
438 writer
, mi_lttng_element_rate_policy_every_n_interval
, every_n_policy
->interval
);
443 /* Close rate_policy_every_n element. */
444 ret
= mi_lttng_writer_close_element(writer
);
453 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
458 struct lttng_rate_policy
*lttng_rate_policy_every_n_create(uint64_t interval
)
460 struct lttng_rate_policy_every_n
*policy
= NULL
;
461 struct lttng_rate_policy
*_policy
= NULL
;
465 * An interval of 0 is invalid since it would never be fired.
470 policy
= zmalloc
<lttng_rate_policy_every_n
>();
475 lttng_rate_policy_init(&policy
->parent
,
476 LTTNG_RATE_POLICY_TYPE_EVERY_N
,
477 lttng_rate_policy_every_n_serialize
,
478 lttng_rate_policy_every_n_is_equal
,
479 lttng_rate_policy_every_n_destroy
,
480 lttng_rate_policy_every_n_copy
,
481 lttng_rate_policy_every_n_mi_serialize
);
483 policy
->interval
= interval
;
485 _policy
= &policy
->parent
;
493 enum lttng_rate_policy_status
494 lttng_rate_policy_every_n_get_interval(const struct lttng_rate_policy
*policy
, uint64_t *interval
)
496 const struct lttng_rate_policy_every_n
*every_n_policy
;
497 enum lttng_rate_policy_status status
;
499 if (!policy
|| !IS_EVERY_N_RATE_POLICY(policy
) || !interval
) {
500 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
504 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
505 *interval
= every_n_policy
->interval
;
506 status
= LTTNG_RATE_POLICY_STATUS_OK
;
512 static bool lttng_rate_policy_every_n_should_execute(const struct lttng_rate_policy
*policy
,
515 const struct lttng_rate_policy_every_n
*every_n_policy
;
516 LTTNG_ASSERT(policy
);
517 bool execute
= false;
519 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
521 if (every_n_policy
->interval
== 0) {
525 execute
= (counter
% every_n_policy
->interval
) == 0;
527 DBG("Policy every N = %" PRIu64
": execution %s. Execution count: %" PRIu64
,
528 every_n_policy
->interval
,
529 execute
? "accepted" : "denied",
537 static struct lttng_rate_policy_once_after_n
*
538 rate_policy_once_after_n_from_rate_policy(struct lttng_rate_policy
*policy
)
540 LTTNG_ASSERT(policy
);
542 return lttng::utils::container_of(policy
, <tng_rate_policy_once_after_n::parent
);
545 static const struct lttng_rate_policy_once_after_n
*
546 rate_policy_once_after_n_from_rate_policy_const(const struct lttng_rate_policy
*policy
)
548 LTTNG_ASSERT(policy
);
550 return lttng::utils::container_of(policy
, <tng_rate_policy_once_after_n::parent
);
552 static int lttng_rate_policy_once_after_n_serialize(struct lttng_rate_policy
*policy
,
553 struct lttng_payload
*payload
)
557 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
558 struct lttng_rate_policy_once_after_n_comm comm
= {};
560 LTTNG_ASSERT(policy
);
561 LTTNG_ASSERT(payload
);
563 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
564 comm
.threshold
= once_after_n_policy
->threshold
;
566 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &comm
, sizeof(comm
));
570 static bool lttng_rate_policy_once_after_n_is_equal(const struct lttng_rate_policy
*_a
,
571 const struct lttng_rate_policy
*_b
)
573 bool is_equal
= false;
574 const struct lttng_rate_policy_once_after_n
*a
, *b
;
576 a
= rate_policy_once_after_n_from_rate_policy_const(_a
);
577 b
= rate_policy_once_after_n_from_rate_policy_const(_b
);
579 if (a
->threshold
!= b
->threshold
) {
589 static void lttng_rate_policy_once_after_n_destroy(struct lttng_rate_policy
*policy
)
591 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
597 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
599 free(once_after_n_policy
);
605 static struct lttng_rate_policy
*
606 lttng_rate_policy_once_after_n_copy(const struct lttng_rate_policy
*source
)
608 struct lttng_rate_policy
*copy
= NULL
;
609 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
615 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(source
);
616 copy
= lttng_rate_policy_once_after_n_create(once_after_n_policy
->threshold
);
622 static enum lttng_error_code
623 lttng_rate_policy_once_after_n_mi_serialize(const struct lttng_rate_policy
*rate_policy
,
624 struct mi_writer
*writer
)
627 enum lttng_error_code ret_code
;
628 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
= NULL
;
630 LTTNG_ASSERT(rate_policy
);
631 LTTNG_ASSERT(IS_ONCE_AFTER_N_RATE_POLICY(rate_policy
));
632 LTTNG_ASSERT(writer
);
634 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(rate_policy
);
636 /* Open rate_policy_once_after_n. */
637 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_rate_policy_once_after_n
);
643 ret
= mi_lttng_writer_write_element_unsigned_int(
645 mi_lttng_element_rate_policy_once_after_n_threshold
,
646 once_after_n_policy
->threshold
);
651 /* Close rate_policy_once_after_n element. */
652 ret
= mi_lttng_writer_close_element(writer
);
661 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
666 struct lttng_rate_policy
*lttng_rate_policy_once_after_n_create(uint64_t threshold
)
668 struct lttng_rate_policy_once_after_n
*policy
= NULL
;
669 struct lttng_rate_policy
*_policy
= NULL
;
671 if (threshold
== 0) {
672 /* threshold is expected to be > 0 */
676 policy
= zmalloc
<lttng_rate_policy_once_after_n
>();
681 lttng_rate_policy_init(&policy
->parent
,
682 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
,
683 lttng_rate_policy_once_after_n_serialize
,
684 lttng_rate_policy_once_after_n_is_equal
,
685 lttng_rate_policy_once_after_n_destroy
,
686 lttng_rate_policy_once_after_n_copy
,
687 lttng_rate_policy_once_after_n_mi_serialize
);
689 policy
->threshold
= threshold
;
691 _policy
= &policy
->parent
;
699 enum lttng_rate_policy_status
700 lttng_rate_policy_once_after_n_get_threshold(const struct lttng_rate_policy
*policy
,
703 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
704 enum lttng_rate_policy_status status
;
706 if (!policy
|| !IS_ONCE_AFTER_N_RATE_POLICY(policy
) || !threshold
) {
707 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
711 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(policy
);
712 *threshold
= once_after_n_policy
->threshold
;
713 status
= LTTNG_RATE_POLICY_STATUS_OK
;
719 struct lttng_rate_policy
*lttng_rate_policy_copy(const struct lttng_rate_policy
*source
)
721 LTTNG_ASSERT(source
->copy
);
722 return source
->copy(source
);
725 static bool lttng_rate_policy_once_after_n_should_execute(const struct lttng_rate_policy
*policy
,
728 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
729 bool execute
= false;
730 LTTNG_ASSERT(policy
);
732 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(policy
);
734 execute
= counter
== once_after_n_policy
->threshold
;
736 DBG("Policy once after N = %" PRIu64
": execution %s. Execution count: %" PRIu64
,
737 once_after_n_policy
->threshold
,
738 execute
? "accepted" : "denied",
741 return counter
== once_after_n_policy
->threshold
;
744 enum lttng_error_code
lttng_rate_policy_mi_serialize(const struct lttng_rate_policy
*rate_policy
,
745 struct mi_writer
*writer
)
748 enum lttng_error_code ret_code
;
750 LTTNG_ASSERT(rate_policy
);
751 LTTNG_ASSERT(writer
);
752 LTTNG_ASSERT(rate_policy
->mi_serialize
);
754 /* Open rate policy element. */
755 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_rate_policy
);
760 /* Serialize underlying rate policy. */
761 ret_code
= rate_policy
->mi_serialize(rate_policy
, writer
);
762 if (ret_code
!= LTTNG_OK
) {
766 /* Close rate policy element. */
767 ret
= mi_lttng_writer_close_element(writer
);
776 ret_code
= LTTNG_ERR_MI_IO_FAIL
;