2 * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/buffer-view.h>
9 #include <common/dynamic-buffer.h>
10 #include <common/error.h>
11 #include <common/macros.h>
12 #include <common/payload-view.h>
13 #include <common/payload.h>
15 #include <lttng/action/firing-policy-internal.h>
16 #include <lttng/action/firing-policy.h>
18 #include <sys/types.h>
20 #define IS_EVERY_N_FIRING_POLICY(policy) \
21 (lttng_firing_policy_get_type(policy) == \
22 LTTNG_FIRING_POLICY_TYPE_EVERY_N)
24 #define IS_ONCE_AFTER_N_FIRING_POLICY(policy) \
25 (lttng_firing_policy_get_type(policy) == \
26 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N)
28 typedef void (*firing_policy_destroy_cb
)(
29 struct lttng_firing_policy
*firing_policy
);
30 typedef int (*firing_policy_serialize_cb
)(
31 struct lttng_firing_policy
*firing_policy
,
32 struct lttng_payload
*payload
);
33 typedef bool (*firing_policy_equal_cb
)(const struct lttng_firing_policy
*a
,
34 const struct lttng_firing_policy
*b
);
35 typedef ssize_t (*firing_policy_create_from_payload_cb
)(
36 struct lttng_payload_view
*view
,
37 struct lttng_firing_policy
**firing_policy
);
38 typedef struct lttng_firing_policy
*(*firing_policy_copy_cb
)(
39 const struct lttng_firing_policy
*source
);
41 struct lttng_firing_policy
{
42 enum lttng_firing_policy_type type
;
43 firing_policy_serialize_cb serialize
;
44 firing_policy_equal_cb equal
;
45 firing_policy_destroy_cb destroy
;
46 firing_policy_copy_cb copy
;
49 struct lttng_firing_policy_every_n
{
50 struct lttng_firing_policy parent
;
54 struct lttng_firing_policy_once_after_n
{
55 struct lttng_firing_policy parent
;
59 struct lttng_firing_policy_comm
{
60 /* enum lttng_firing_policy_type */
61 int8_t firing_policy_type
;
64 struct lttng_firing_policy_once_after_n_comm
{
68 struct lttng_firing_policy_every_n_comm
{
72 /* Forward declaration. */
73 static void lttng_firing_policy_init(struct lttng_firing_policy
*firing_policy
,
74 enum lttng_firing_policy_type type
,
75 firing_policy_serialize_cb serialize
,
76 firing_policy_equal_cb equal
,
77 firing_policy_destroy_cb destroy
,
78 firing_policy_copy_cb copy
);
80 /* Forward declaration. Every n */
81 static bool lttng_firing_policy_every_n_should_execute(
82 const struct lttng_firing_policy
*policy
, uint64_t counter
);
84 /* Forward declaration. Once after N */
85 static bool lttng_firing_policy_once_after_n_should_execute(
86 const struct lttng_firing_policy
*policy
, uint64_t counter
);
89 const char *lttng_firing_policy_type_string(
90 enum lttng_firing_policy_type firing_policy_type
)
92 switch (firing_policy_type
) {
93 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
95 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
96 return "ONCE-AFTER-N";
102 enum lttng_firing_policy_type
lttng_firing_policy_get_type(
103 const struct lttng_firing_policy
*policy
)
105 return policy
? policy
->type
: LTTNG_FIRING_POLICY_TYPE_UNKNOWN
;
109 void lttng_firing_policy_init(struct lttng_firing_policy
*firing_policy
,
110 enum lttng_firing_policy_type type
,
111 firing_policy_serialize_cb serialize
,
112 firing_policy_equal_cb equal
,
113 firing_policy_destroy_cb destroy
,
114 firing_policy_copy_cb copy
)
116 firing_policy
->type
= type
;
117 firing_policy
->serialize
= serialize
;
118 firing_policy
->equal
= equal
;
119 firing_policy
->destroy
= destroy
;
120 firing_policy
->copy
= copy
;
123 void lttng_firing_policy_destroy(struct lttng_firing_policy
*firing_policy
)
125 if (!firing_policy
) {
129 firing_policy
->destroy(firing_policy
);
133 int lttng_firing_policy_serialize(struct lttng_firing_policy
*firing_policy
,
134 struct lttng_payload
*payload
)
137 const struct lttng_firing_policy_comm firing_policy_comm
= {
138 .firing_policy_type
= (int8_t) firing_policy
->type
,
141 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &firing_policy_comm
,
142 sizeof(firing_policy_comm
));
147 ret
= firing_policy
->serialize(firing_policy
, payload
);
155 static ssize_t
lttng_firing_policy_once_after_n_create_from_payload(
156 struct lttng_payload_view
*view
,
157 struct lttng_firing_policy
**firing_policy
)
159 ssize_t consumed_len
= -1;
160 struct lttng_firing_policy
*policy
= NULL
;
161 const struct lttng_firing_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
|| !firing_policy
) {
170 if (!lttng_payload_view_is_valid(&comm_view
)) {
171 /* Payload not large enough to contain the header. */
176 comm
= (const struct lttng_firing_policy_once_after_n_comm
*)
177 comm_view
.buffer
.data
;
179 policy
= lttng_firing_policy_once_after_n_create(comm
->threshold
);
180 if (policy
== NULL
) {
185 *firing_policy
= policy
;
186 consumed_len
= sizeof(*comm
);
192 static ssize_t
lttng_firing_policy_every_n_create_from_payload(
193 struct lttng_payload_view
*view
,
194 struct lttng_firing_policy
**firing_policy
)
196 ssize_t consumed_len
= -1;
197 struct lttng_firing_policy
*policy
= NULL
;
198 const struct lttng_firing_policy_every_n_comm
*comm
;
199 const struct lttng_payload_view comm_view
=
200 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
202 if (!view
|| !firing_policy
) {
207 if (!lttng_payload_view_is_valid(&comm_view
)) {
208 /* Payload not large enough to contain the header. */
213 comm
= (const struct lttng_firing_policy_every_n_comm
*)
214 comm_view
.buffer
.data
;
216 policy
= lttng_firing_policy_every_n_create(comm
->interval
);
217 if (policy
== NULL
) {
222 *firing_policy
= policy
;
223 consumed_len
= sizeof(*comm
);
230 ssize_t
lttng_firing_policy_create_from_payload(struct lttng_payload_view
*view
,
231 struct lttng_firing_policy
**firing_policy
)
233 ssize_t consumed_len
, specific_firing_policy_consumed_len
;
234 firing_policy_create_from_payload_cb create_from_payload_cb
;
235 const struct lttng_firing_policy_comm
*firing_policy_comm
;
236 const struct lttng_payload_view firing_policy_comm_view
=
237 lttng_payload_view_from_view(
238 view
, 0, sizeof(*firing_policy_comm
));
240 if (!view
|| !firing_policy
) {
245 if (!lttng_payload_view_is_valid(&firing_policy_comm_view
)) {
246 /* Payload not large enough to contain the header. */
252 (const struct lttng_firing_policy_comm
*)
253 firing_policy_comm_view
.buffer
.data
;
255 DBG("Create firing_policy from payload: firing-policy-type=%s",
256 lttng_firing_policy_type_string(
257 firing_policy_comm
->firing_policy_type
));
259 switch (firing_policy_comm
->firing_policy_type
) {
260 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
261 create_from_payload_cb
=
262 lttng_firing_policy_every_n_create_from_payload
;
264 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
265 create_from_payload_cb
=
266 lttng_firing_policy_once_after_n_create_from_payload
;
269 ERR("Failed to create firing-policy from payload, unhandled firing-policy type: firing-policy-type=%u (%s)",
270 firing_policy_comm
->firing_policy_type
,
271 lttng_firing_policy_type_string(firing_policy_comm
->firing_policy_type
));
278 * Create buffer view for the firing_policy-type-specific data.
280 struct lttng_payload_view specific_firing_policy_view
=
281 lttng_payload_view_from_view(view
,
282 sizeof(struct lttng_firing_policy_comm
),
285 specific_firing_policy_consumed_len
= create_from_payload_cb(
286 &specific_firing_policy_view
, firing_policy
);
289 if (specific_firing_policy_consumed_len
< 0) {
290 ERR("Failed to create specific firing_policy from buffer");
295 LTTNG_ASSERT(*firing_policy
);
297 consumed_len
= sizeof(struct lttng_firing_policy_comm
) +
298 specific_firing_policy_consumed_len
;
305 bool lttng_firing_policy_is_equal(const struct lttng_firing_policy
*a
,
306 const struct lttng_firing_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
);
330 bool lttng_firing_policy_should_execute(
331 const struct lttng_firing_policy
*policy
, uint64_t counter
)
333 switch (policy
->type
) {
334 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
335 return lttng_firing_policy_every_n_should_execute(
337 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
338 return lttng_firing_policy_once_after_n_should_execute(
347 static const struct lttng_firing_policy_every_n
*
348 firing_policy_every_n_from_firing_policy_const(
349 const struct lttng_firing_policy
*policy
)
351 LTTNG_ASSERT(policy
);
353 return container_of(policy
, const struct lttng_firing_policy_every_n
,
357 static int lttng_firing_policy_every_n_serialize(
358 struct lttng_firing_policy
*policy
,
359 struct lttng_payload
*payload
)
362 const struct lttng_firing_policy_every_n
*every_n_policy
;
363 struct lttng_firing_policy_every_n_comm comm
= {};
365 LTTNG_ASSERT(policy
);
366 LTTNG_ASSERT(payload
);
368 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
369 comm
.interval
= every_n_policy
->interval
;
371 ret
= lttng_dynamic_buffer_append(
372 &payload
->buffer
, &comm
, sizeof(comm
));
376 static bool lttng_firing_policy_every_n_is_equal(
377 const struct lttng_firing_policy
*_a
,
378 const struct lttng_firing_policy
*_b
)
380 bool is_equal
= false;
381 const struct lttng_firing_policy_every_n
*a
, *b
;
383 a
= firing_policy_every_n_from_firing_policy_const(_a
);
384 b
= firing_policy_every_n_from_firing_policy_const(_b
);
386 if (a
->interval
!= b
->interval
) {
396 static void lttng_firing_policy_every_n_destroy(
397 struct lttng_firing_policy
*policy
)
399 /* Nothing type-specific to release. */
403 static struct lttng_firing_policy
*lttng_firing_policy_every_n_copy(
404 const struct lttng_firing_policy
*source
)
406 struct lttng_firing_policy
*copy
= NULL
;
407 const struct lttng_firing_policy_every_n
*every_n_policy
;
413 every_n_policy
= firing_policy_every_n_from_firing_policy_const(source
);
414 copy
= lttng_firing_policy_every_n_create(
415 every_n_policy
->interval
);
422 struct lttng_firing_policy
*lttng_firing_policy_every_n_create(
425 struct lttng_firing_policy_every_n
*policy
= NULL
;
429 * An interval of 0 is invalid since it would never be fired.
434 policy
= zmalloc(sizeof(struct lttng_firing_policy_every_n
));
439 lttng_firing_policy_init(&policy
->parent
,
440 LTTNG_FIRING_POLICY_TYPE_EVERY_N
,
441 lttng_firing_policy_every_n_serialize
,
442 lttng_firing_policy_every_n_is_equal
,
443 lttng_firing_policy_every_n_destroy
,
444 lttng_firing_policy_every_n_copy
);
446 policy
->interval
= interval
;
449 return policy
? &policy
->parent
: NULL
;
453 enum lttng_firing_policy_status
lttng_firing_policy_every_n_get_interval(
454 const struct lttng_firing_policy
*policy
, uint64_t *interval
)
456 const struct lttng_firing_policy_every_n
*every_n_policy
;
457 enum lttng_firing_policy_status status
;
459 if (!policy
|| !IS_EVERY_N_FIRING_POLICY(policy
) || !interval
) {
460 status
= LTTNG_FIRING_POLICY_STATUS_INVALID
;
464 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
465 *interval
= every_n_policy
->interval
;
466 status
= LTTNG_FIRING_POLICY_STATUS_OK
;
472 static bool lttng_firing_policy_every_n_should_execute(
473 const struct lttng_firing_policy
*policy
, uint64_t counter
)
475 const struct lttng_firing_policy_every_n
*every_n_policy
;
476 LTTNG_ASSERT(policy
);
477 bool execute
= false;
479 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
481 if (every_n_policy
->interval
== 0) {
485 execute
= (counter
% every_n_policy
->interval
) == 0;
487 DBG("Policy every N = %" PRIu64
488 ": execution %s. Execution count: %" PRIu64
,
489 every_n_policy
->interval
,
490 execute
? "accepted" : "denied", counter
);
497 static const struct lttng_firing_policy_once_after_n
*
498 firing_policy_once_after_n_from_firing_policy_const(
499 const struct lttng_firing_policy
*policy
)
501 LTTNG_ASSERT(policy
);
503 return container_of(policy
, struct lttng_firing_policy_once_after_n
,
507 static int lttng_firing_policy_once_after_n_serialize(
508 struct lttng_firing_policy
*policy
,
509 struct lttng_payload
*payload
)
512 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
513 struct lttng_firing_policy_once_after_n_comm comm
= {};
515 LTTNG_ASSERT(policy
);
516 LTTNG_ASSERT(payload
);
518 once_after_n_policy
=
519 firing_policy_once_after_n_from_firing_policy_const(
521 comm
.threshold
= once_after_n_policy
->threshold
;
523 ret
= lttng_dynamic_buffer_append(
524 &payload
->buffer
, &comm
, sizeof(comm
));
528 static bool lttng_firing_policy_once_after_n_is_equal(
529 const struct lttng_firing_policy
*_a
,
530 const struct lttng_firing_policy
*_b
)
532 bool is_equal
= false;
533 const struct lttng_firing_policy_once_after_n
*a
, *b
;
535 a
= firing_policy_once_after_n_from_firing_policy_const(_a
);
536 b
= firing_policy_once_after_n_from_firing_policy_const(_b
);
538 if (a
->threshold
!= b
->threshold
) {
548 static void lttng_firing_policy_once_after_n_destroy(
549 struct lttng_firing_policy
*policy
)
551 /* Nothing type specific to release. */
555 static struct lttng_firing_policy
*lttng_firing_policy_once_after_n_copy(
556 const struct lttng_firing_policy
*source
)
558 struct lttng_firing_policy
*copy
= NULL
;
559 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
565 once_after_n_policy
=
566 firing_policy_once_after_n_from_firing_policy_const(
568 copy
= lttng_firing_policy_once_after_n_create(
569 once_after_n_policy
->threshold
);
576 struct lttng_firing_policy
*lttng_firing_policy_once_after_n_create(
579 struct lttng_firing_policy_once_after_n
*policy
= NULL
;
581 if (threshold
== 0) {
582 /* threshold is expected to be > 0 */
586 policy
= zmalloc(sizeof(struct lttng_firing_policy_once_after_n
));
591 lttng_firing_policy_init(&policy
->parent
,
592 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
,
593 lttng_firing_policy_once_after_n_serialize
,
594 lttng_firing_policy_once_after_n_is_equal
,
595 lttng_firing_policy_once_after_n_destroy
,
596 lttng_firing_policy_once_after_n_copy
);
598 policy
->threshold
= threshold
;
601 return policy
? &policy
->parent
: NULL
;
605 enum lttng_firing_policy_status
lttng_firing_policy_once_after_n_get_threshold(
606 const struct lttng_firing_policy
*policy
, uint64_t *threshold
)
608 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
609 enum lttng_firing_policy_status status
;
611 if (!policy
|| !IS_ONCE_AFTER_N_FIRING_POLICY(policy
) || !threshold
) {
612 status
= LTTNG_FIRING_POLICY_STATUS_INVALID
;
616 once_after_n_policy
=
617 firing_policy_once_after_n_from_firing_policy_const(
619 *threshold
= once_after_n_policy
->threshold
;
620 status
= LTTNG_FIRING_POLICY_STATUS_OK
;
627 struct lttng_firing_policy
*lttng_firing_policy_copy(
628 const struct lttng_firing_policy
*source
)
630 LTTNG_ASSERT(source
->copy
);
631 return source
->copy(source
);
634 static bool lttng_firing_policy_once_after_n_should_execute(
635 const struct lttng_firing_policy
*policy
, uint64_t counter
)
637 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
638 bool execute
= false;
639 LTTNG_ASSERT(policy
);
641 once_after_n_policy
=
642 firing_policy_once_after_n_from_firing_policy_const(
645 execute
= counter
== once_after_n_policy
->threshold
;
647 DBG("Policy once after N = %" PRIu64
648 ": execution %s. Execution count: %" PRIu64
,
649 once_after_n_policy
->threshold
,
650 execute
? "accepted" : "denied", counter
);
652 return counter
== once_after_n_policy
->threshold
;