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/firing-policy-internal.h>
17 #include <lttng/action/firing-policy.h>
19 #include <sys/types.h>
21 #define IS_EVERY_N_FIRING_POLICY(policy) \
22 (lttng_firing_policy_get_type(policy) == \
23 LTTNG_FIRING_POLICY_TYPE_EVERY_N)
25 #define IS_ONCE_AFTER_N_FIRING_POLICY(policy) \
26 (lttng_firing_policy_get_type(policy) == \
27 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N)
29 typedef void (*firing_policy_destroy_cb
)(
30 struct lttng_firing_policy
*firing_policy
);
31 typedef int (*firing_policy_serialize_cb
)(
32 struct lttng_firing_policy
*firing_policy
,
33 struct lttng_payload
*payload
);
34 typedef bool (*firing_policy_equal_cb
)(const struct lttng_firing_policy
*a
,
35 const struct lttng_firing_policy
*b
);
36 typedef ssize_t (*firing_policy_create_from_payload_cb
)(
37 struct lttng_payload_view
*view
,
38 struct lttng_firing_policy
**firing_policy
);
39 typedef struct lttng_firing_policy
*(*firing_policy_copy_cb
)(
40 const struct lttng_firing_policy
*source
);
42 struct lttng_firing_policy
{
43 enum lttng_firing_policy_type type
;
44 firing_policy_serialize_cb serialize
;
45 firing_policy_equal_cb equal
;
46 firing_policy_destroy_cb destroy
;
47 firing_policy_copy_cb copy
;
50 struct lttng_firing_policy_every_n
{
51 struct lttng_firing_policy parent
;
55 struct lttng_firing_policy_once_after_n
{
56 struct lttng_firing_policy parent
;
60 struct lttng_firing_policy_comm
{
61 /* enum lttng_firing_policy_type */
62 int8_t firing_policy_type
;
65 struct lttng_firing_policy_once_after_n_comm
{
69 struct lttng_firing_policy_every_n_comm
{
73 /* Forward declaration. */
74 static void lttng_firing_policy_init(struct lttng_firing_policy
*firing_policy
,
75 enum lttng_firing_policy_type type
,
76 firing_policy_serialize_cb serialize
,
77 firing_policy_equal_cb equal
,
78 firing_policy_destroy_cb destroy
,
79 firing_policy_copy_cb copy
);
81 /* Forward declaration. Every n */
82 static bool lttng_firing_policy_every_n_should_execute(
83 const struct lttng_firing_policy
*policy
, uint64_t counter
);
85 /* Forward declaration. Once after N */
86 static bool lttng_firing_policy_once_after_n_should_execute(
87 const struct lttng_firing_policy
*policy
, uint64_t counter
);
90 const char *lttng_firing_policy_type_string(
91 enum lttng_firing_policy_type firing_policy_type
)
93 switch (firing_policy_type
) {
94 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
96 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
97 return "ONCE-AFTER-N";
103 enum lttng_firing_policy_type
lttng_firing_policy_get_type(
104 const struct lttng_firing_policy
*policy
)
106 return policy
? policy
->type
: LTTNG_FIRING_POLICY_TYPE_UNKNOWN
;
110 void lttng_firing_policy_init(struct lttng_firing_policy
*firing_policy
,
111 enum lttng_firing_policy_type type
,
112 firing_policy_serialize_cb serialize
,
113 firing_policy_equal_cb equal
,
114 firing_policy_destroy_cb destroy
,
115 firing_policy_copy_cb copy
)
117 firing_policy
->type
= type
;
118 firing_policy
->serialize
= serialize
;
119 firing_policy
->equal
= equal
;
120 firing_policy
->destroy
= destroy
;
121 firing_policy
->copy
= copy
;
124 void lttng_firing_policy_destroy(struct lttng_firing_policy
*firing_policy
)
126 if (!firing_policy
) {
130 firing_policy
->destroy(firing_policy
);
134 int lttng_firing_policy_serialize(struct lttng_firing_policy
*firing_policy
,
135 struct lttng_payload
*payload
)
138 const struct lttng_firing_policy_comm firing_policy_comm
= {
139 .firing_policy_type
= (int8_t) firing_policy
->type
,
142 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &firing_policy_comm
,
143 sizeof(firing_policy_comm
));
148 ret
= firing_policy
->serialize(firing_policy
, payload
);
156 static ssize_t
lttng_firing_policy_once_after_n_create_from_payload(
157 struct lttng_payload_view
*view
,
158 struct lttng_firing_policy
**firing_policy
)
160 ssize_t consumed_len
= -1;
161 struct lttng_firing_policy
*policy
= NULL
;
162 const struct lttng_firing_policy_once_after_n_comm
*comm
;
163 const struct lttng_payload_view comm_view
=
164 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
166 if (!view
|| !firing_policy
) {
171 if (!lttng_payload_view_is_valid(&comm_view
)) {
172 /* Payload not large enough to contain the header. */
177 comm
= (const struct lttng_firing_policy_once_after_n_comm
*)
178 comm_view
.buffer
.data
;
180 policy
= lttng_firing_policy_once_after_n_create(comm
->threshold
);
181 if (policy
== NULL
) {
186 *firing_policy
= policy
;
187 consumed_len
= sizeof(*comm
);
193 static ssize_t
lttng_firing_policy_every_n_create_from_payload(
194 struct lttng_payload_view
*view
,
195 struct lttng_firing_policy
**firing_policy
)
197 ssize_t consumed_len
= -1;
198 struct lttng_firing_policy
*policy
= NULL
;
199 const struct lttng_firing_policy_every_n_comm
*comm
;
200 const struct lttng_payload_view comm_view
=
201 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
203 if (!view
|| !firing_policy
) {
208 if (!lttng_payload_view_is_valid(&comm_view
)) {
209 /* Payload not large enough to contain the header. */
214 comm
= (const struct lttng_firing_policy_every_n_comm
*)
215 comm_view
.buffer
.data
;
217 policy
= lttng_firing_policy_every_n_create(comm
->interval
);
218 if (policy
== NULL
) {
223 *firing_policy
= policy
;
224 consumed_len
= sizeof(*comm
);
231 ssize_t
lttng_firing_policy_create_from_payload(struct lttng_payload_view
*view
,
232 struct lttng_firing_policy
**firing_policy
)
234 ssize_t consumed_len
, specific_firing_policy_consumed_len
;
235 firing_policy_create_from_payload_cb create_from_payload_cb
;
236 const struct lttng_firing_policy_comm
*firing_policy_comm
;
237 const struct lttng_payload_view firing_policy_comm_view
=
238 lttng_payload_view_from_view(
239 view
, 0, sizeof(*firing_policy_comm
));
241 if (!view
|| !firing_policy
) {
246 if (!lttng_payload_view_is_valid(&firing_policy_comm_view
)) {
247 /* Payload not large enough to contain the header. */
253 (const struct lttng_firing_policy_comm
*)
254 firing_policy_comm_view
.buffer
.data
;
256 DBG("Create firing_policy from payload: firing-policy-type=%s",
257 lttng_firing_policy_type_string(
258 firing_policy_comm
->firing_policy_type
));
260 switch (firing_policy_comm
->firing_policy_type
) {
261 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
262 create_from_payload_cb
=
263 lttng_firing_policy_every_n_create_from_payload
;
265 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
266 create_from_payload_cb
=
267 lttng_firing_policy_once_after_n_create_from_payload
;
270 ERR("Failed to create firing-policy from payload, unhandled firing-policy type: firing-policy-type=%u (%s)",
271 firing_policy_comm
->firing_policy_type
,
272 lttng_firing_policy_type_string(firing_policy_comm
->firing_policy_type
));
279 * Create buffer view for the firing_policy-type-specific data.
281 struct lttng_payload_view specific_firing_policy_view
=
282 lttng_payload_view_from_view(view
,
283 sizeof(struct lttng_firing_policy_comm
),
286 specific_firing_policy_consumed_len
= create_from_payload_cb(
287 &specific_firing_policy_view
, firing_policy
);
290 if (specific_firing_policy_consumed_len
< 0) {
291 ERR("Failed to create specific firing_policy from buffer");
296 assert(*firing_policy
);
298 consumed_len
= sizeof(struct lttng_firing_policy_comm
) +
299 specific_firing_policy_consumed_len
;
306 bool lttng_firing_policy_is_equal(const struct lttng_firing_policy
*a
,
307 const struct lttng_firing_policy
*b
)
309 bool is_equal
= false;
315 if (a
->type
!= b
->type
) {
325 is_equal
= a
->equal(a
, b
);
331 bool lttng_firing_policy_should_execute(
332 const struct lttng_firing_policy
*policy
, uint64_t counter
)
334 switch (policy
->type
) {
335 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
336 return lttng_firing_policy_every_n_should_execute(
338 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
339 return lttng_firing_policy_once_after_n_should_execute(
348 static const struct lttng_firing_policy_every_n
*
349 firing_policy_every_n_from_firing_policy_const(
350 const struct lttng_firing_policy
*policy
)
354 return container_of(policy
, const struct lttng_firing_policy_every_n
,
358 static int lttng_firing_policy_every_n_serialize(
359 struct lttng_firing_policy
*policy
,
360 struct lttng_payload
*payload
)
363 const struct lttng_firing_policy_every_n
*every_n_policy
;
364 struct lttng_firing_policy_every_n_comm comm
= {};
369 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
370 comm
.interval
= every_n_policy
->interval
;
372 ret
= lttng_dynamic_buffer_append(
373 &payload
->buffer
, &comm
, sizeof(comm
));
377 static bool lttng_firing_policy_every_n_is_equal(
378 const struct lttng_firing_policy
*_a
,
379 const struct lttng_firing_policy
*_b
)
381 bool is_equal
= false;
382 const struct lttng_firing_policy_every_n
*a
, *b
;
384 a
= firing_policy_every_n_from_firing_policy_const(_a
);
385 b
= firing_policy_every_n_from_firing_policy_const(_b
);
387 if (a
->interval
!= b
->interval
) {
397 static void lttng_firing_policy_every_n_destroy(
398 struct lttng_firing_policy
*policy
)
400 /* Nothing type-specific to release. */
404 static struct lttng_firing_policy
*lttng_firing_policy_every_n_copy(
405 const struct lttng_firing_policy
*source
)
407 struct lttng_firing_policy
*copy
= NULL
;
408 const struct lttng_firing_policy_every_n
*every_n_policy
;
414 every_n_policy
= firing_policy_every_n_from_firing_policy_const(source
);
415 copy
= lttng_firing_policy_every_n_create(
416 every_n_policy
->interval
);
423 struct lttng_firing_policy
*lttng_firing_policy_every_n_create(
426 struct lttng_firing_policy_every_n
*policy
= NULL
;
430 * An interval of 0 is invalid since it would never be fired.
435 policy
= zmalloc(sizeof(struct lttng_firing_policy_every_n
));
440 lttng_firing_policy_init(&policy
->parent
,
441 LTTNG_FIRING_POLICY_TYPE_EVERY_N
,
442 lttng_firing_policy_every_n_serialize
,
443 lttng_firing_policy_every_n_is_equal
,
444 lttng_firing_policy_every_n_destroy
,
445 lttng_firing_policy_every_n_copy
);
447 policy
->interval
= interval
;
450 return policy
? &policy
->parent
: NULL
;
454 enum lttng_firing_policy_status
lttng_firing_policy_every_n_get_interval(
455 const struct lttng_firing_policy
*policy
, uint64_t *interval
)
457 const struct lttng_firing_policy_every_n
*every_n_policy
;
458 enum lttng_firing_policy_status status
;
460 if (!policy
|| !IS_EVERY_N_FIRING_POLICY(policy
) || !interval
) {
461 status
= LTTNG_FIRING_POLICY_STATUS_INVALID
;
465 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
466 *interval
= every_n_policy
->interval
;
467 status
= LTTNG_FIRING_POLICY_STATUS_OK
;
473 static bool lttng_firing_policy_every_n_should_execute(
474 const struct lttng_firing_policy
*policy
, uint64_t counter
)
476 const struct lttng_firing_policy_every_n
*every_n_policy
;
478 bool execute
= false;
480 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
482 if (every_n_policy
->interval
== 0) {
486 execute
= (counter
% every_n_policy
->interval
) == 0;
488 DBG("Policy every N = %" PRIu64
489 ": execution %s. Execution count: %" PRIu64
,
490 every_n_policy
->interval
,
491 execute
? "accepted" : "denied", counter
);
498 static const struct lttng_firing_policy_once_after_n
*
499 firing_policy_once_after_n_from_firing_policy_const(
500 const struct lttng_firing_policy
*policy
)
504 return container_of(policy
, struct lttng_firing_policy_once_after_n
,
508 static int lttng_firing_policy_once_after_n_serialize(
509 struct lttng_firing_policy
*policy
,
510 struct lttng_payload
*payload
)
513 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
514 struct lttng_firing_policy_once_after_n_comm comm
= {};
519 once_after_n_policy
=
520 firing_policy_once_after_n_from_firing_policy_const(
522 comm
.threshold
= once_after_n_policy
->threshold
;
524 ret
= lttng_dynamic_buffer_append(
525 &payload
->buffer
, &comm
, sizeof(comm
));
529 static bool lttng_firing_policy_once_after_n_is_equal(
530 const struct lttng_firing_policy
*_a
,
531 const struct lttng_firing_policy
*_b
)
533 bool is_equal
= false;
534 const struct lttng_firing_policy_once_after_n
*a
, *b
;
536 a
= firing_policy_once_after_n_from_firing_policy_const(_a
);
537 b
= firing_policy_once_after_n_from_firing_policy_const(_b
);
539 if (a
->threshold
!= b
->threshold
) {
549 static void lttng_firing_policy_once_after_n_destroy(
550 struct lttng_firing_policy
*policy
)
552 /* Nothing type specific to release. */
556 static struct lttng_firing_policy
*lttng_firing_policy_once_after_n_copy(
557 const struct lttng_firing_policy
*source
)
559 struct lttng_firing_policy
*copy
= NULL
;
560 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
566 once_after_n_policy
=
567 firing_policy_once_after_n_from_firing_policy_const(
569 copy
= lttng_firing_policy_once_after_n_create(
570 once_after_n_policy
->threshold
);
577 struct lttng_firing_policy
*lttng_firing_policy_once_after_n_create(
580 struct lttng_firing_policy_once_after_n
*policy
= NULL
;
582 if (threshold
== 0) {
583 /* threshold is expected to be > 0 */
587 policy
= zmalloc(sizeof(struct lttng_firing_policy_once_after_n
));
592 lttng_firing_policy_init(&policy
->parent
,
593 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
,
594 lttng_firing_policy_once_after_n_serialize
,
595 lttng_firing_policy_once_after_n_is_equal
,
596 lttng_firing_policy_once_after_n_destroy
,
597 lttng_firing_policy_once_after_n_copy
);
599 policy
->threshold
= threshold
;
602 return policy
? &policy
->parent
: NULL
;
606 enum lttng_firing_policy_status
lttng_firing_policy_once_after_n_get_threshold(
607 const struct lttng_firing_policy
*policy
, uint64_t *threshold
)
609 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
610 enum lttng_firing_policy_status status
;
612 if (!policy
|| !IS_ONCE_AFTER_N_FIRING_POLICY(policy
) || !threshold
) {
613 status
= LTTNG_FIRING_POLICY_STATUS_INVALID
;
617 once_after_n_policy
=
618 firing_policy_once_after_n_from_firing_policy_const(
620 *threshold
= once_after_n_policy
->threshold
;
621 status
= LTTNG_FIRING_POLICY_STATUS_OK
;
628 struct lttng_firing_policy
*lttng_firing_policy_copy(
629 const struct lttng_firing_policy
*source
)
631 assert(source
->copy
);
632 return source
->copy(source
);
635 static bool lttng_firing_policy_once_after_n_should_execute(
636 const struct lttng_firing_policy
*policy
, uint64_t counter
)
638 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
639 bool execute
= false;
642 once_after_n_policy
=
643 firing_policy_once_after_n_from_firing_policy_const(
646 execute
= counter
== once_after_n_policy
->threshold
;
648 DBG("Policy once after N = %" PRIu64
649 ": execution %s. Execution count: %" PRIu64
,
650 once_after_n_policy
->threshold
,
651 execute
? "accepted" : "denied", counter
);
653 return counter
== once_after_n_policy
->threshold
;