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>
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
);
38 typedef enum lttng_error_code (*rate_policy_mi_serialize_cb
)(
39 const struct lttng_rate_policy
*rate_policy
,
40 struct mi_writer
*writer
);
42 struct lttng_rate_policy
{
43 enum lttng_rate_policy_type type
;
44 rate_policy_serialize_cb serialize
;
45 rate_policy_equal_cb equal
;
46 rate_policy_destroy_cb destroy
;
47 rate_policy_copy_cb copy
;
48 rate_policy_mi_serialize_cb mi_serialize
;
52 struct lttng_rate_policy_every_n
{
53 struct lttng_rate_policy parent
;
57 struct lttng_rate_policy_once_after_n
{
58 struct lttng_rate_policy parent
;
62 struct lttng_rate_policy_comm
{
63 /* enum lttng_rate_policy_type */
64 int8_t rate_policy_type
;
67 struct lttng_rate_policy_once_after_n_comm
{
71 struct lttng_rate_policy_every_n_comm
{
76 /* Forward declaration. */
77 static void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
78 enum lttng_rate_policy_type type
,
79 rate_policy_serialize_cb serialize
,
80 rate_policy_equal_cb equal
,
81 rate_policy_destroy_cb destroy
,
82 rate_policy_copy_cb copy
,
83 rate_policy_mi_serialize_cb mi
);
85 /* Forward declaration. Every n */
86 static bool lttng_rate_policy_every_n_should_execute(
87 const struct lttng_rate_policy
*policy
, uint64_t counter
);
89 /* Forward declaration. Once after N */
90 static bool lttng_rate_policy_once_after_n_should_execute(
91 const struct lttng_rate_policy
*policy
, uint64_t counter
);
93 const char *lttng_rate_policy_type_string(
94 enum lttng_rate_policy_type rate_policy_type
)
96 switch (rate_policy_type
) {
97 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
99 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
100 return "ONCE-AFTER-N";
106 enum lttng_rate_policy_type
lttng_rate_policy_get_type(
107 const struct lttng_rate_policy
*policy
)
109 return policy
? policy
->type
: LTTNG_RATE_POLICY_TYPE_UNKNOWN
;
112 void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
113 enum lttng_rate_policy_type type
,
114 rate_policy_serialize_cb serialize
,
115 rate_policy_equal_cb equal
,
116 rate_policy_destroy_cb destroy
,
117 rate_policy_copy_cb copy
,
118 rate_policy_mi_serialize_cb mi
)
120 rate_policy
->type
= type
;
121 rate_policy
->serialize
= serialize
;
122 rate_policy
->equal
= equal
;
123 rate_policy
->destroy
= destroy
;
124 rate_policy
->copy
= copy
;
125 rate_policy
->mi_serialize
= mi
;
128 void lttng_rate_policy_destroy(struct lttng_rate_policy
*rate_policy
)
134 rate_policy
->destroy(rate_policy
);
137 int lttng_rate_policy_serialize(struct lttng_rate_policy
*rate_policy
,
138 struct lttng_payload
*payload
)
141 struct lttng_rate_policy_comm rate_policy_comm
= {
142 .rate_policy_type
= (int8_t) rate_policy
->type
,
145 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &rate_policy_comm
,
146 sizeof(rate_policy_comm
));
151 ret
= rate_policy
->serialize(rate_policy
, payload
);
159 static ssize_t
lttng_rate_policy_once_after_n_create_from_payload(
160 struct lttng_payload_view
*view
,
161 struct lttng_rate_policy
**rate_policy
)
163 ssize_t consumed_len
= -1;
164 struct lttng_rate_policy
*policy
= NULL
;
165 const struct lttng_rate_policy_once_after_n_comm
*comm
;
166 const struct lttng_payload_view comm_view
=
167 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
169 if (!view
|| !rate_policy
) {
174 if (!lttng_payload_view_is_valid(&comm_view
)) {
175 /* Payload not large enough to contain the header. */
180 comm
= (const struct lttng_rate_policy_once_after_n_comm
*)
181 comm_view
.buffer
.data
;
183 policy
= lttng_rate_policy_once_after_n_create(comm
->threshold
);
184 if (policy
== NULL
) {
189 *rate_policy
= policy
;
190 consumed_len
= sizeof(*comm
);
196 static ssize_t
lttng_rate_policy_every_n_create_from_payload(
197 struct lttng_payload_view
*view
,
198 struct lttng_rate_policy
**rate_policy
)
200 ssize_t consumed_len
= -1;
201 struct lttng_rate_policy
*policy
= NULL
;
202 const struct lttng_rate_policy_every_n_comm
*comm
;
203 const struct lttng_payload_view comm_view
=
204 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
206 if (!view
|| !rate_policy
) {
211 if (!lttng_payload_view_is_valid(&comm_view
)) {
212 /* Payload not large enough to contain the header. */
217 comm
= (const struct lttng_rate_policy_every_n_comm
*)
218 comm_view
.buffer
.data
;
220 policy
= lttng_rate_policy_every_n_create(comm
->interval
);
221 if (policy
== NULL
) {
226 *rate_policy
= policy
;
227 consumed_len
= sizeof(*comm
);
233 ssize_t
lttng_rate_policy_create_from_payload(struct lttng_payload_view
*view
,
234 struct lttng_rate_policy
**rate_policy
)
236 ssize_t consumed_len
, specific_rate_policy_consumed_len
;
237 rate_policy_create_from_payload_cb create_from_payload_cb
;
238 const struct lttng_rate_policy_comm
*rate_policy_comm
;
239 const struct lttng_payload_view rate_policy_comm_view
=
240 lttng_payload_view_from_view(
241 view
, 0, sizeof(*rate_policy_comm
));
243 if (!view
|| !rate_policy
) {
248 if (!lttng_payload_view_is_valid(&rate_policy_comm_view
)) {
249 /* Payload not large enough to contain the header. */
254 rate_policy_comm
= (const struct lttng_rate_policy_comm
*)
255 rate_policy_comm_view
.buffer
.data
;
257 DBG("Create rate_policy from payload: rate-policy-type=%s",
258 lttng_rate_policy_type_string(
259 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
261 switch (rate_policy_comm
->rate_policy_type
) {
262 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
263 create_from_payload_cb
=
264 lttng_rate_policy_every_n_create_from_payload
;
266 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
267 create_from_payload_cb
=
268 lttng_rate_policy_once_after_n_create_from_payload
;
271 ERR("Failed to create rate-policy from payload, unhandled rate-policy type: rate-policy-type=%u (%s)",
272 rate_policy_comm
->rate_policy_type
,
273 lttng_rate_policy_type_string(
274 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
280 /* Create buffer view for the rate_policy-type-specific data.
282 struct lttng_payload_view specific_rate_policy_view
=
283 lttng_payload_view_from_view(view
,
284 sizeof(struct lttng_rate_policy_comm
),
287 specific_rate_policy_consumed_len
= create_from_payload_cb(
288 &specific_rate_policy_view
, rate_policy
);
290 if (specific_rate_policy_consumed_len
< 0) {
291 ERR("Failed to create specific rate_policy from buffer.");
296 LTTNG_ASSERT(*rate_policy
);
298 consumed_len
= sizeof(struct lttng_rate_policy_comm
) +
299 specific_rate_policy_consumed_len
;
305 bool lttng_rate_policy_is_equal(const struct lttng_rate_policy
*a
,
306 const struct lttng_rate_policy
*b
)
308 bool is_equal
= false;
314 if (a
->type
!= b
->type
) {
323 LTTNG_ASSERT(a
->equal
);
324 is_equal
= a
->equal(a
, b
);
329 bool lttng_rate_policy_should_execute(
330 const struct lttng_rate_policy
*policy
, uint64_t counter
)
332 switch (policy
->type
) {
333 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
334 return lttng_rate_policy_every_n_should_execute(
336 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
337 return lttng_rate_policy_once_after_n_should_execute(
346 static struct lttng_rate_policy_every_n
*rate_policy_every_n_from_rate_policy(
347 struct lttng_rate_policy
*policy
)
349 LTTNG_ASSERT(policy
);
351 return lttng::utils::container_of(policy
, <tng_rate_policy_every_n::parent
);
354 static const struct lttng_rate_policy_every_n
*
355 rate_policy_every_n_from_rate_policy_const(
356 const struct lttng_rate_policy
*policy
)
358 LTTNG_ASSERT(policy
);
360 return lttng::utils::container_of(policy
, <tng_rate_policy_every_n::parent
);
363 static int lttng_rate_policy_every_n_serialize(
364 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
368 struct lttng_rate_policy_every_n
*every_n_policy
;
369 struct lttng_rate_policy_every_n_comm comm
= {};
371 LTTNG_ASSERT(policy
);
372 LTTNG_ASSERT(payload
);
374 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
375 comm
.interval
= every_n_policy
->interval
;
377 ret
= lttng_dynamic_buffer_append(
378 &payload
->buffer
, &comm
, sizeof(comm
));
382 static bool lttng_rate_policy_every_n_is_equal(
383 const struct lttng_rate_policy
*_a
,
384 const struct lttng_rate_policy
*_b
)
386 bool is_equal
= false;
387 const struct lttng_rate_policy_every_n
*a
, *b
;
389 a
= rate_policy_every_n_from_rate_policy_const(_a
);
390 b
= rate_policy_every_n_from_rate_policy_const(_b
);
392 if (a
->interval
!= b
->interval
) {
402 static void lttng_rate_policy_every_n_destroy(struct lttng_rate_policy
*policy
)
404 struct lttng_rate_policy_every_n
*every_n_policy
;
410 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
412 free(every_n_policy
);
418 static struct lttng_rate_policy
*lttng_rate_policy_every_n_copy(
419 const struct lttng_rate_policy
*source
)
421 struct lttng_rate_policy
*copy
= NULL
;
422 const struct lttng_rate_policy_every_n
*every_n_policy
;
428 every_n_policy
= rate_policy_every_n_from_rate_policy_const(source
);
429 copy
= lttng_rate_policy_every_n_create(every_n_policy
->interval
);
435 static enum lttng_error_code
lttng_rate_policy_every_n_mi_serialize(
436 const struct lttng_rate_policy
*rate_policy
,
437 struct mi_writer
*writer
)
440 enum lttng_error_code ret_code
;
441 const struct lttng_rate_policy_every_n
*every_n_policy
= NULL
;
443 LTTNG_ASSERT(rate_policy
);
444 LTTNG_ASSERT(IS_EVERY_N_RATE_POLICY(rate_policy
));
445 LTTNG_ASSERT(writer
);
447 every_n_policy
= rate_policy_every_n_from_rate_policy_const(
450 /* Open rate_policy_every_n element. */
451 ret
= mi_lttng_writer_open_element(
452 writer
, mi_lttng_element_rate_policy_every_n
);
458 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
459 mi_lttng_element_rate_policy_every_n_interval
,
460 every_n_policy
->interval
);
465 /* Close rate_policy_every_n element. */
466 ret
= mi_lttng_writer_close_element(writer
);
475 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
480 struct lttng_rate_policy
*lttng_rate_policy_every_n_create(uint64_t interval
)
482 struct lttng_rate_policy_every_n
*policy
= NULL
;
483 struct lttng_rate_policy
*_policy
= NULL
;
487 * An interval of 0 is invalid since it would never be fired.
492 policy
= zmalloc
<lttng_rate_policy_every_n
>();
497 lttng_rate_policy_init(&policy
->parent
, LTTNG_RATE_POLICY_TYPE_EVERY_N
,
498 lttng_rate_policy_every_n_serialize
,
499 lttng_rate_policy_every_n_is_equal
,
500 lttng_rate_policy_every_n_destroy
,
501 lttng_rate_policy_every_n_copy
,
502 lttng_rate_policy_every_n_mi_serialize
);
504 policy
->interval
= interval
;
506 _policy
= &policy
->parent
;
514 enum lttng_rate_policy_status
lttng_rate_policy_every_n_get_interval(
515 const struct lttng_rate_policy
*policy
, uint64_t *interval
)
517 const struct lttng_rate_policy_every_n
*every_n_policy
;
518 enum lttng_rate_policy_status status
;
520 if (!policy
|| !IS_EVERY_N_RATE_POLICY(policy
) || !interval
) {
521 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
525 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
526 *interval
= every_n_policy
->interval
;
527 status
= LTTNG_RATE_POLICY_STATUS_OK
;
533 static bool lttng_rate_policy_every_n_should_execute(
534 const struct lttng_rate_policy
*policy
, uint64_t counter
)
536 const struct lttng_rate_policy_every_n
*every_n_policy
;
537 LTTNG_ASSERT(policy
);
538 bool execute
= false;
540 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
542 if (every_n_policy
->interval
== 0) {
546 execute
= (counter
% every_n_policy
->interval
) == 0;
548 DBG("Policy every N = %" PRIu64
549 ": execution %s. Execution count: %" PRIu64
,
550 every_n_policy
->interval
,
551 execute
? "accepted" : "denied", counter
);
558 static struct lttng_rate_policy_once_after_n
*
559 rate_policy_once_after_n_from_rate_policy(struct lttng_rate_policy
*policy
)
561 LTTNG_ASSERT(policy
);
563 return lttng::utils::container_of(
564 policy
, <tng_rate_policy_once_after_n::parent
);
567 static const struct lttng_rate_policy_once_after_n
*
568 rate_policy_once_after_n_from_rate_policy_const(
569 const struct lttng_rate_policy
*policy
)
571 LTTNG_ASSERT(policy
);
573 return lttng::utils::container_of(
574 policy
, <tng_rate_policy_once_after_n::parent
);
576 static int lttng_rate_policy_once_after_n_serialize(
577 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
581 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
582 struct lttng_rate_policy_once_after_n_comm comm
= {};
584 LTTNG_ASSERT(policy
);
585 LTTNG_ASSERT(payload
);
587 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
588 comm
.threshold
= once_after_n_policy
->threshold
;
590 ret
= lttng_dynamic_buffer_append(
591 &payload
->buffer
, &comm
, sizeof(comm
));
595 static bool lttng_rate_policy_once_after_n_is_equal(
596 const struct lttng_rate_policy
*_a
,
597 const struct lttng_rate_policy
*_b
)
599 bool is_equal
= false;
600 const struct lttng_rate_policy_once_after_n
*a
, *b
;
602 a
= rate_policy_once_after_n_from_rate_policy_const(_a
);
603 b
= rate_policy_once_after_n_from_rate_policy_const(_b
);
605 if (a
->threshold
!= b
->threshold
) {
615 static void lttng_rate_policy_once_after_n_destroy(
616 struct lttng_rate_policy
*policy
)
618 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
624 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
626 free(once_after_n_policy
);
632 static struct lttng_rate_policy
*lttng_rate_policy_once_after_n_copy(
633 const struct lttng_rate_policy
*source
)
635 struct lttng_rate_policy
*copy
= NULL
;
636 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
642 once_after_n_policy
=
643 rate_policy_once_after_n_from_rate_policy_const(source
);
644 copy
= lttng_rate_policy_once_after_n_create(
645 once_after_n_policy
->threshold
);
651 static enum lttng_error_code
lttng_rate_policy_once_after_n_mi_serialize(
652 const struct lttng_rate_policy
*rate_policy
,
653 struct mi_writer
*writer
)
656 enum lttng_error_code ret_code
;
657 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
= NULL
;
659 LTTNG_ASSERT(rate_policy
);
660 LTTNG_ASSERT(IS_ONCE_AFTER_N_RATE_POLICY(rate_policy
));
661 LTTNG_ASSERT(writer
);
663 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(
666 /* Open rate_policy_once_after_n. */
667 ret
= mi_lttng_writer_open_element(
668 writer
, mi_lttng_element_rate_policy_once_after_n
);
674 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
675 mi_lttng_element_rate_policy_once_after_n_threshold
,
676 once_after_n_policy
->threshold
);
681 /* Close rate_policy_once_after_n element. */
682 ret
= mi_lttng_writer_close_element(writer
);
691 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
696 struct lttng_rate_policy
*lttng_rate_policy_once_after_n_create(
699 struct lttng_rate_policy_once_after_n
*policy
= NULL
;
700 struct lttng_rate_policy
*_policy
= NULL
;
702 if (threshold
== 0) {
703 /* threshold is expected to be > 0 */
707 policy
= zmalloc
<lttng_rate_policy_once_after_n
>();
712 lttng_rate_policy_init(&policy
->parent
,
713 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
,
714 lttng_rate_policy_once_after_n_serialize
,
715 lttng_rate_policy_once_after_n_is_equal
,
716 lttng_rate_policy_once_after_n_destroy
,
717 lttng_rate_policy_once_after_n_copy
,
718 lttng_rate_policy_once_after_n_mi_serialize
);
720 policy
->threshold
= threshold
;
722 _policy
= &policy
->parent
;
730 enum lttng_rate_policy_status
lttng_rate_policy_once_after_n_get_threshold(
731 const struct lttng_rate_policy
*policy
, uint64_t *threshold
)
733 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
734 enum lttng_rate_policy_status status
;
736 if (!policy
|| !IS_ONCE_AFTER_N_RATE_POLICY(policy
) || !threshold
) {
737 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
741 once_after_n_policy
=
742 rate_policy_once_after_n_from_rate_policy_const(policy
);
743 *threshold
= once_after_n_policy
->threshold
;
744 status
= LTTNG_RATE_POLICY_STATUS_OK
;
750 struct lttng_rate_policy
*lttng_rate_policy_copy(
751 const struct lttng_rate_policy
*source
)
753 LTTNG_ASSERT(source
->copy
);
754 return source
->copy(source
);
757 static bool lttng_rate_policy_once_after_n_should_execute(
758 const struct lttng_rate_policy
*policy
, uint64_t counter
)
760 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
761 bool execute
= false;
762 LTTNG_ASSERT(policy
);
764 once_after_n_policy
=
765 rate_policy_once_after_n_from_rate_policy_const(policy
);
767 execute
= counter
== once_after_n_policy
->threshold
;
769 DBG("Policy once after N = %" PRIu64
770 ": execution %s. Execution count: %" PRIu64
,
771 once_after_n_policy
->threshold
,
772 execute
? "accepted" : "denied", counter
);
774 return counter
== once_after_n_policy
->threshold
;
777 enum lttng_error_code
lttng_rate_policy_mi_serialize(
778 const struct lttng_rate_policy
*rate_policy
,
779 struct mi_writer
*writer
)
782 enum lttng_error_code ret_code
;
784 LTTNG_ASSERT(rate_policy
);
785 LTTNG_ASSERT(writer
);
786 LTTNG_ASSERT(rate_policy
->mi_serialize
);
788 /* Open rate policy element. */
789 ret
= mi_lttng_writer_open_element(
790 writer
, mi_lttng_element_rate_policy
);
795 /* Serialize underlying rate policy. */
796 ret_code
= rate_policy
->mi_serialize(rate_policy
, writer
);
797 if (ret_code
!= LTTNG_OK
) {
801 /* Close rate policy element. */
802 ret
= mi_lttng_writer_close_element(writer
);
811 ret_code
= LTTNG_ERR_MI_IO_FAIL
;