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/mi-lttng.h>
14 #include <common/payload-view.h>
15 #include <common/payload.h>
17 #include <lttng/action/rate-policy-internal.h>
18 #include <lttng/action/rate-policy.h>
20 #include <sys/types.h>
22 #define IS_EVERY_N_RATE_POLICY(policy) \
23 (lttng_rate_policy_get_type(policy) == LTTNG_RATE_POLICY_TYPE_EVERY_N)
25 #define IS_ONCE_AFTER_N_RATE_POLICY(policy) \
26 (lttng_rate_policy_get_type(policy) == \
27 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
)(
35 struct lttng_payload_view
*view
,
36 struct lttng_rate_policy
**rate_policy
);
37 typedef struct lttng_rate_policy
*(*rate_policy_copy_cb
)(
38 const struct lttng_rate_policy
*source
);
39 typedef enum lttng_error_code (*rate_policy_mi_serialize_cb
)(
40 const struct lttng_rate_policy
*rate_policy
,
41 struct mi_writer
*writer
);
43 struct lttng_rate_policy
{
44 enum lttng_rate_policy_type type
;
45 rate_policy_serialize_cb serialize
;
46 rate_policy_equal_cb equal
;
47 rate_policy_destroy_cb destroy
;
48 rate_policy_copy_cb copy
;
49 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
{
75 /* Forward declaration. */
76 static void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
77 enum lttng_rate_policy_type type
,
78 rate_policy_serialize_cb serialize
,
79 rate_policy_equal_cb equal
,
80 rate_policy_destroy_cb destroy
,
81 rate_policy_copy_cb copy
,
82 rate_policy_mi_serialize_cb mi
);
84 /* Forward declaration. Every n */
85 static bool lttng_rate_policy_every_n_should_execute(
86 const struct lttng_rate_policy
*policy
, uint64_t counter
);
88 /* Forward declaration. Once after N */
89 static bool lttng_rate_policy_once_after_n_should_execute(
90 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
;
113 void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
114 enum lttng_rate_policy_type type
,
115 rate_policy_serialize_cb serialize
,
116 rate_policy_equal_cb equal
,
117 rate_policy_destroy_cb destroy
,
118 rate_policy_copy_cb copy
,
119 rate_policy_mi_serialize_cb mi
)
121 rate_policy
->type
= type
;
122 rate_policy
->serialize
= serialize
;
123 rate_policy
->equal
= equal
;
124 rate_policy
->destroy
= destroy
;
125 rate_policy
->copy
= copy
;
126 rate_policy
->mi_serialize
= mi
;
129 void lttng_rate_policy_destroy(struct lttng_rate_policy
*rate_policy
)
135 rate_policy
->destroy(rate_policy
);
139 int lttng_rate_policy_serialize(struct lttng_rate_policy
*rate_policy
,
140 struct lttng_payload
*payload
)
143 struct lttng_rate_policy_comm rate_policy_comm
= {
144 .rate_policy_type
= (int8_t) rate_policy
->type
,
147 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &rate_policy_comm
,
148 sizeof(rate_policy_comm
));
153 ret
= rate_policy
->serialize(rate_policy
, payload
);
161 static ssize_t
lttng_rate_policy_once_after_n_create_from_payload(
162 struct lttng_payload_view
*view
,
163 struct lttng_rate_policy
**rate_policy
)
165 ssize_t consumed_len
= -1;
166 struct lttng_rate_policy
*policy
= NULL
;
167 const struct lttng_rate_policy_once_after_n_comm
*comm
;
168 const struct lttng_payload_view comm_view
=
169 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
171 if (!view
|| !rate_policy
) {
176 if (!lttng_payload_view_is_valid(&comm_view
)) {
177 /* Payload not large enough to contain the header. */
182 comm
= (const struct lttng_rate_policy_once_after_n_comm
*)
183 comm_view
.buffer
.data
;
185 policy
= lttng_rate_policy_once_after_n_create(comm
->threshold
);
186 if (policy
== NULL
) {
191 *rate_policy
= policy
;
192 consumed_len
= sizeof(*comm
);
198 static ssize_t
lttng_rate_policy_every_n_create_from_payload(
199 struct lttng_payload_view
*view
,
200 struct lttng_rate_policy
**rate_policy
)
202 ssize_t consumed_len
= -1;
203 struct lttng_rate_policy
*policy
= NULL
;
204 const struct lttng_rate_policy_every_n_comm
*comm
;
205 const struct lttng_payload_view comm_view
=
206 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
208 if (!view
|| !rate_policy
) {
213 if (!lttng_payload_view_is_valid(&comm_view
)) {
214 /* Payload not large enough to contain the header. */
219 comm
= (const struct lttng_rate_policy_every_n_comm
*)
220 comm_view
.buffer
.data
;
222 policy
= lttng_rate_policy_every_n_create(comm
->interval
);
223 if (policy
== NULL
) {
228 *rate_policy
= policy
;
229 consumed_len
= sizeof(*comm
);
236 ssize_t
lttng_rate_policy_create_from_payload(struct lttng_payload_view
*view
,
237 struct lttng_rate_policy
**rate_policy
)
239 ssize_t consumed_len
, specific_rate_policy_consumed_len
;
240 rate_policy_create_from_payload_cb create_from_payload_cb
;
241 const struct lttng_rate_policy_comm
*rate_policy_comm
;
242 const struct lttng_payload_view rate_policy_comm_view
=
243 lttng_payload_view_from_view(
244 view
, 0, sizeof(*rate_policy_comm
));
246 if (!view
|| !rate_policy
) {
251 if (!lttng_payload_view_is_valid(&rate_policy_comm_view
)) {
252 /* Payload not large enough to contain the header. */
257 rate_policy_comm
= (const struct lttng_rate_policy_comm
*)
258 rate_policy_comm_view
.buffer
.data
;
260 DBG("Create rate_policy from payload: rate-policy-type=%s",
261 lttng_rate_policy_type_string(
262 rate_policy_comm
->rate_policy_type
));
264 switch (rate_policy_comm
->rate_policy_type
) {
265 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
266 create_from_payload_cb
=
267 lttng_rate_policy_every_n_create_from_payload
;
269 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
270 create_from_payload_cb
=
271 lttng_rate_policy_once_after_n_create_from_payload
;
274 ERR("Failed to create rate-policy from payload, unhandled rate-policy type: rate-policy-type=%u (%s)",
275 rate_policy_comm
->rate_policy_type
,
276 lttng_rate_policy_type_string(
277 rate_policy_comm
->rate_policy_type
));
283 /* Create buffer view for the rate_policy-type-specific data.
285 struct lttng_payload_view specific_rate_policy_view
=
286 lttng_payload_view_from_view(view
,
287 sizeof(struct lttng_rate_policy_comm
),
290 specific_rate_policy_consumed_len
= create_from_payload_cb(
291 &specific_rate_policy_view
, rate_policy
);
293 if (specific_rate_policy_consumed_len
< 0) {
294 ERR("Failed to create specific rate_policy from buffer.");
299 assert(*rate_policy
);
301 consumed_len
= sizeof(struct lttng_rate_policy_comm
) +
302 specific_rate_policy_consumed_len
;
309 bool lttng_rate_policy_is_equal(const struct lttng_rate_policy
*a
,
310 const struct lttng_rate_policy
*b
)
312 bool is_equal
= false;
318 if (a
->type
!= b
->type
) {
328 is_equal
= a
->equal(a
, b
);
334 bool lttng_rate_policy_should_execute(
335 const struct lttng_rate_policy
*policy
, uint64_t counter
)
337 switch (policy
->type
) {
338 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
339 return lttng_rate_policy_every_n_should_execute(
341 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
342 return lttng_rate_policy_once_after_n_should_execute(
351 static struct lttng_rate_policy_every_n
*rate_policy_every_n_from_rate_policy(
352 struct lttng_rate_policy
*policy
)
356 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
359 static const struct lttng_rate_policy_every_n
*
360 rate_policy_every_n_from_rate_policy_const(
361 const struct lttng_rate_policy
*policy
)
365 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
368 static int lttng_rate_policy_every_n_serialize(
369 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
373 struct lttng_rate_policy_every_n
*every_n_policy
;
374 struct lttng_rate_policy_every_n_comm comm
= {};
379 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
380 comm
.interval
= every_n_policy
->interval
;
382 ret
= lttng_dynamic_buffer_append(
383 &payload
->buffer
, &comm
, sizeof(comm
));
387 static bool lttng_rate_policy_every_n_is_equal(
388 const struct lttng_rate_policy
*_a
,
389 const struct lttng_rate_policy
*_b
)
391 bool is_equal
= false;
392 const struct lttng_rate_policy_every_n
*a
, *b
;
394 a
= rate_policy_every_n_from_rate_policy_const(_a
);
395 b
= rate_policy_every_n_from_rate_policy_const(_b
);
397 if (a
->interval
!= b
->interval
) {
407 static void lttng_rate_policy_every_n_destroy(struct lttng_rate_policy
*policy
)
409 struct lttng_rate_policy_every_n
*every_n_policy
;
415 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
417 free(every_n_policy
);
423 static struct lttng_rate_policy
*lttng_rate_policy_every_n_copy(
424 const struct lttng_rate_policy
*source
)
426 struct lttng_rate_policy
*copy
= NULL
;
427 const struct lttng_rate_policy_every_n
*every_n_policy
;
433 every_n_policy
= rate_policy_every_n_from_rate_policy_const(source
);
434 copy
= lttng_rate_policy_every_n_create(every_n_policy
->interval
);
440 static enum lttng_error_code
lttng_rate_policy_every_n_mi_serialize(
441 const struct lttng_rate_policy
*rate_policy
,
442 struct mi_writer
*writer
)
445 enum lttng_error_code ret_code
;
446 const struct lttng_rate_policy_every_n
*every_n_policy
= NULL
;
449 assert(IS_EVERY_N_RATE_POLICY(rate_policy
));
452 every_n_policy
= rate_policy_every_n_from_rate_policy_const(
455 /* Open rate_policy_every_n element. */
456 ret
= mi_lttng_writer_open_element(
457 writer
, mi_lttng_element_rate_policy_every_n
);
463 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
464 mi_lttng_element_rate_policy_every_n_interval
,
465 every_n_policy
->interval
);
470 /* Close rate_policy_every_n element. */
471 ret
= mi_lttng_writer_close_element(writer
);
480 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
485 struct lttng_rate_policy
*lttng_rate_policy_every_n_create(uint64_t interval
)
487 struct lttng_rate_policy_every_n
*policy
= NULL
;
488 struct lttng_rate_policy
*_policy
= NULL
;
492 * An interval of 0 is invalid since it would never be fired.
497 policy
= zmalloc(sizeof(struct lttng_rate_policy_every_n
));
502 lttng_rate_policy_init(&policy
->parent
, LTTNG_RATE_POLICY_TYPE_EVERY_N
,
503 lttng_rate_policy_every_n_serialize
,
504 lttng_rate_policy_every_n_is_equal
,
505 lttng_rate_policy_every_n_destroy
,
506 lttng_rate_policy_every_n_copy
,
507 lttng_rate_policy_every_n_mi_serialize
);
509 policy
->interval
= interval
;
511 _policy
= &policy
->parent
;
520 enum lttng_rate_policy_status
lttng_rate_policy_every_n_get_interval(
521 const struct lttng_rate_policy
*policy
, uint64_t *interval
)
523 const struct lttng_rate_policy_every_n
*every_n_policy
;
524 enum lttng_rate_policy_status status
;
526 if (!policy
|| !IS_EVERY_N_RATE_POLICY(policy
) || !interval
) {
527 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
531 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
532 *interval
= every_n_policy
->interval
;
533 status
= LTTNG_RATE_POLICY_STATUS_OK
;
539 static bool lttng_rate_policy_every_n_should_execute(
540 const struct lttng_rate_policy
*policy
, uint64_t counter
)
542 const struct lttng_rate_policy_every_n
*every_n_policy
;
544 bool execute
= false;
546 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
548 if (every_n_policy
->interval
== 0) {
552 execute
= (counter
% every_n_policy
->interval
) == 0;
554 DBG("Policy every N = %" PRIu64
555 ": execution %s. Execution count: %" PRIu64
,
556 every_n_policy
->interval
,
557 execute
? "accepted" : "denied", counter
);
564 static struct lttng_rate_policy_once_after_n
*
565 rate_policy_once_after_n_from_rate_policy(struct lttng_rate_policy
*policy
)
570 policy
, struct lttng_rate_policy_once_after_n
, parent
);
573 static const struct lttng_rate_policy_once_after_n
*
574 rate_policy_once_after_n_from_rate_policy_const(
575 const struct lttng_rate_policy
*policy
)
580 policy
, struct lttng_rate_policy_once_after_n
, parent
);
582 static int lttng_rate_policy_once_after_n_serialize(
583 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
587 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
588 struct lttng_rate_policy_once_after_n_comm comm
= {};
593 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
594 comm
.threshold
= once_after_n_policy
->threshold
;
596 ret
= lttng_dynamic_buffer_append(
597 &payload
->buffer
, &comm
, sizeof(comm
));
601 static bool lttng_rate_policy_once_after_n_is_equal(
602 const struct lttng_rate_policy
*_a
,
603 const struct lttng_rate_policy
*_b
)
605 bool is_equal
= false;
606 const struct lttng_rate_policy_once_after_n
*a
, *b
;
608 a
= rate_policy_once_after_n_from_rate_policy_const(_a
);
609 b
= rate_policy_once_after_n_from_rate_policy_const(_b
);
611 if (a
->threshold
!= b
->threshold
) {
621 static void lttng_rate_policy_once_after_n_destroy(
622 struct lttng_rate_policy
*policy
)
624 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
630 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
632 free(once_after_n_policy
);
638 static struct lttng_rate_policy
*lttng_rate_policy_once_after_n_copy(
639 const struct lttng_rate_policy
*source
)
641 struct lttng_rate_policy
*copy
= NULL
;
642 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
648 once_after_n_policy
=
649 rate_policy_once_after_n_from_rate_policy_const(source
);
650 copy
= lttng_rate_policy_once_after_n_create(
651 once_after_n_policy
->threshold
);
657 static enum lttng_error_code
lttng_rate_policy_once_after_n_mi_serialize(
658 const struct lttng_rate_policy
*rate_policy
,
659 struct mi_writer
*writer
)
662 enum lttng_error_code ret_code
;
663 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
= NULL
;
666 assert(IS_ONCE_AFTER_N_RATE_POLICY(rate_policy
));
669 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(
672 /* Open rate_policy_once_after_n. */
673 ret
= mi_lttng_writer_open_element(
674 writer
, mi_lttng_element_rate_policy_once_after_n
);
680 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
681 mi_lttng_element_rate_policy_once_after_n_threshold
,
682 once_after_n_policy
->threshold
);
687 /* Close rate_policy_once_after_n element. */
688 ret
= mi_lttng_writer_close_element(writer
);
697 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
702 struct lttng_rate_policy
*lttng_rate_policy_once_after_n_create(
705 struct lttng_rate_policy_once_after_n
*policy
= NULL
;
706 struct lttng_rate_policy
*_policy
= NULL
;
708 if (threshold
== 0) {
709 /* threshold is expected to be > 0 */
713 policy
= zmalloc(sizeof(struct lttng_rate_policy_once_after_n
));
718 lttng_rate_policy_init(&policy
->parent
,
719 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
,
720 lttng_rate_policy_once_after_n_serialize
,
721 lttng_rate_policy_once_after_n_is_equal
,
722 lttng_rate_policy_once_after_n_destroy
,
723 lttng_rate_policy_once_after_n_copy
,
724 lttng_rate_policy_once_after_n_mi_serialize
);
726 policy
->threshold
= threshold
;
728 _policy
= &policy
->parent
;
737 enum lttng_rate_policy_status
lttng_rate_policy_once_after_n_get_threshold(
738 const struct lttng_rate_policy
*policy
, uint64_t *threshold
)
740 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
741 enum lttng_rate_policy_status status
;
743 if (!policy
|| !IS_ONCE_AFTER_N_RATE_POLICY(policy
) || !threshold
) {
744 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
748 once_after_n_policy
=
749 rate_policy_once_after_n_from_rate_policy_const(policy
);
750 *threshold
= once_after_n_policy
->threshold
;
751 status
= LTTNG_RATE_POLICY_STATUS_OK
;
758 struct lttng_rate_policy
*lttng_rate_policy_copy(
759 const struct lttng_rate_policy
*source
)
761 assert(source
->copy
);
762 return source
->copy(source
);
765 static bool lttng_rate_policy_once_after_n_should_execute(
766 const struct lttng_rate_policy
*policy
, uint64_t counter
)
768 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
769 bool execute
= false;
772 once_after_n_policy
=
773 rate_policy_once_after_n_from_rate_policy_const(policy
);
775 execute
= counter
== once_after_n_policy
->threshold
;
777 DBG("Policy once after N = %" PRIu64
778 ": execution %s. Execution count: %" PRIu64
,
779 once_after_n_policy
->threshold
,
780 execute
? "accepted" : "denied", counter
);
782 return counter
== once_after_n_policy
->threshold
;
786 enum lttng_error_code
lttng_rate_policy_mi_serialize(
787 const struct lttng_rate_policy
*rate_policy
,
788 struct mi_writer
*writer
)
791 enum lttng_error_code ret_code
;
795 assert(rate_policy
->mi_serialize
);
797 /* Open rate policy element. */
798 ret
= mi_lttng_writer_open_element(
799 writer
, mi_lttng_element_rate_policy
);
804 /* Serialize underlying rate policy. */
805 ret_code
= rate_policy
->mi_serialize(rate_policy
, writer
);
806 if (ret_code
!= LTTNG_OK
) {
810 /* Close rate policy element. */
811 ret
= mi_lttng_writer_close_element(writer
);
820 ret_code
= LTTNG_ERR_MI_IO_FAIL
;