Implement firing policy for the snapshot session action
[lttng-tools.git] / src / common / actions / snapshot-session.c
1 /*
2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <assert.h>
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/payload-view.h>
12 #include <common/payload.h>
13 #include <common/snapshot.h>
14 #include <inttypes.h>
15 #include <lttng/action/action-internal.h>
16 #include <lttng/action/firing-policy-internal.h>
17 #include <lttng/action/firing-policy.h>
18 #include <lttng/action/snapshot-session-internal.h>
19 #include <lttng/action/snapshot-session.h>
20 #include <lttng/snapshot-internal.h>
21 #include <lttng/snapshot.h>
22
23 #define IS_SNAPSHOT_SESSION_ACTION(action) \
24 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
25
26 struct lttng_action_snapshot_session {
27 struct lttng_action parent;
28
29 /* Owned by this. */
30 char *session_name;
31
32 /*
33 * When non-NULL, use this custom output when taking the snapshot,
34 * rather than the session's registered snapshot output.
35 *
36 * Owned by this.
37 */
38 struct lttng_snapshot_output *output;
39 struct lttng_firing_policy *policy;
40 };
41
42 struct lttng_action_snapshot_session_comm {
43 /* All string lengths include the trailing \0. */
44 uint32_t session_name_len;
45 uint32_t snapshot_output_len;
46 uint32_t firing_policy_len;
47
48 /*
49 * Variable data (all strings are null-terminated):
50 *
51 * - session name string
52 * - snapshot output object
53 * - policy object
54 */
55 char data[];
56 } LTTNG_PACKED;
57
58 static struct lttng_action_snapshot_session *
59 action_snapshot_session_from_action(struct lttng_action *action)
60 {
61 assert(action);
62
63 return container_of(
64 action, struct lttng_action_snapshot_session, parent);
65 }
66
67 static const struct lttng_action_snapshot_session *
68 action_snapshot_session_from_action_const(const struct lttng_action *action)
69 {
70 assert(action);
71
72 return container_of(
73 action, struct lttng_action_snapshot_session, parent);
74 }
75
76 static bool lttng_action_snapshot_session_validate(struct lttng_action *action)
77 {
78 bool valid = false;
79 struct lttng_action_snapshot_session *action_snapshot_session;
80
81 if (!action) {
82 goto end;
83 }
84
85 action_snapshot_session = action_snapshot_session_from_action(action);
86
87 /* A non-empty session name is mandatory. */
88 if (!action_snapshot_session->session_name ||
89 strlen(action_snapshot_session->session_name) == 0) {
90 goto end;
91 }
92
93 if (action_snapshot_session->output &&
94 !lttng_snapshot_output_validate(action_snapshot_session->output)) {
95 goto end;
96 }
97
98 valid = true;
99 end:
100 return valid;
101 }
102
103 static bool lttng_action_snapshot_session_is_equal(
104 const struct lttng_action *_a, const struct lttng_action *_b)
105 {
106 bool is_equal = false;
107 const struct lttng_action_snapshot_session *a, *b;
108
109 a = action_snapshot_session_from_action_const(_a);
110 b = action_snapshot_session_from_action_const(_b);
111
112 /* Action is not valid if this is not true. */
113 assert(a->session_name);
114 assert(b->session_name);
115 if (strcmp(a->session_name, b->session_name)) {
116 goto end;
117 }
118
119 if (a->output && b->output &&
120 !lttng_snapshot_output_is_equal(a->output, b->output)) {
121 goto end;
122 } else if (!!a->output != !!b->output) {
123 goto end;
124 }
125
126 is_equal = lttng_firing_policy_is_equal(a->policy, b->policy);
127 end:
128 return is_equal;
129 }
130
131 static size_t serialize_strlen(const char *str)
132 {
133 return str ? strlen(str) + 1 : 0;
134 }
135
136 static int lttng_action_snapshot_session_serialize(
137 struct lttng_action *action, struct lttng_payload *payload)
138 {
139 struct lttng_action_snapshot_session *action_snapshot_session;
140 struct lttng_action_snapshot_session_comm comm = {};
141 int ret;
142 size_t size_before_comm;
143
144 assert(action);
145 assert(payload);
146
147 size_before_comm = payload->buffer.size;
148
149 action_snapshot_session = action_snapshot_session_from_action(action);
150 comm.session_name_len =
151 serialize_strlen(action_snapshot_session->session_name);
152
153 /* Add header. */
154 ret = lttng_dynamic_buffer_append(
155 &payload->buffer, &comm, sizeof(comm));
156 if (ret) {
157 goto end;
158 }
159
160 assert(action_snapshot_session->session_name);
161 DBG("Serializing snapshot session action: session-name: %s",
162 action_snapshot_session->session_name);
163
164 /* Add session name. */
165 ret = lttng_dynamic_buffer_append(&payload->buffer,
166 action_snapshot_session->session_name,
167 comm.session_name_len);
168 if (ret) {
169 goto end;
170 }
171
172 /* Serialize the snapshot output object, if any. */
173 if (action_snapshot_session->output) {
174 const size_t size_before_output = payload->buffer.size;
175 struct lttng_action_snapshot_session_comm *comm_in_payload;
176
177 ret = lttng_snapshot_output_serialize(
178 action_snapshot_session->output,
179 payload);
180 if (ret) {
181 goto end;
182 }
183
184 comm_in_payload = (typeof(comm_in_payload))(
185 payload->buffer.data + size_before_comm);
186 /* Adjust action length in header. */
187 comm_in_payload->snapshot_output_len =
188 payload->buffer.size - size_before_output;
189 }
190
191 /* Serialize the firing policy. */
192 {
193 const size_t size_before_output = payload->buffer.size;
194 struct lttng_action_snapshot_session_comm *comm_in_payload;
195
196 ret = lttng_firing_policy_serialize(
197 action_snapshot_session->policy, payload);
198 if (ret) {
199 ret = -1;
200 goto end;
201 }
202
203 comm_in_payload = (typeof(comm_in_payload))(
204 payload->buffer.data + size_before_comm);
205 /* Adjust firing policy length in header. */
206 comm_in_payload->firing_policy_len =
207 payload->buffer.size - size_before_output;
208 }
209
210 end:
211 return ret;
212 }
213
214 static void lttng_action_snapshot_session_destroy(struct lttng_action *action)
215 {
216 struct lttng_action_snapshot_session *action_snapshot_session;
217
218 if (!action) {
219 goto end;
220 }
221
222 action_snapshot_session = action_snapshot_session_from_action(action);
223
224 free(action_snapshot_session->session_name);
225 lttng_snapshot_output_destroy(action_snapshot_session->output);
226 lttng_firing_policy_destroy(action_snapshot_session->policy);
227 free(action_snapshot_session);
228
229 end:
230 return;
231 }
232
233 ssize_t lttng_action_snapshot_session_create_from_payload(
234 struct lttng_payload_view *view,
235 struct lttng_action **p_action)
236 {
237 ssize_t consumed_len;
238 const char *variable_data;
239 struct lttng_action *action;
240 enum lttng_action_status status;
241 struct lttng_snapshot_output *snapshot_output = NULL;
242 struct lttng_firing_policy *policy = NULL;
243 const struct lttng_action_snapshot_session_comm *comm;
244 const struct lttng_payload_view snapshot_session_comm_view =
245 lttng_payload_view_from_view(
246 view, 0, sizeof(*comm));
247
248 action = lttng_action_snapshot_session_create();
249 if (!action) {
250 goto error;
251 }
252
253 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view)) {
254 /* Payload not large enough to contain the header. */
255 goto error;
256 }
257
258 comm = (typeof(comm)) snapshot_session_comm_view.buffer.data;
259 variable_data = (const char *) &comm->data;
260
261 consumed_len = sizeof(struct lttng_action_snapshot_session_comm);
262
263 if (!lttng_buffer_view_contains_string(
264 &view->buffer, variable_data, comm->session_name_len)) {
265 goto error;
266 }
267
268 status = lttng_action_snapshot_session_set_session_name(
269 action, variable_data);
270 if (status != LTTNG_ACTION_STATUS_OK) {
271 goto error;
272 }
273
274 variable_data += comm->session_name_len;
275 consumed_len += comm->session_name_len;
276
277 /* If there is a snapshot output object, deserialize it. */
278 if (comm->snapshot_output_len > 0) {
279 ssize_t snapshot_output_consumed_len;
280 enum lttng_action_status action_status;
281 struct lttng_payload_view snapshot_output_buffer_view =
282 lttng_payload_view_from_view(view, consumed_len,
283 comm->snapshot_output_len);
284
285 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view)) {
286 ERR("Failed to create buffer view for snapshot output.");
287 goto error;
288 }
289
290 snapshot_output_consumed_len =
291 lttng_snapshot_output_create_from_payload(
292 &snapshot_output_buffer_view,
293 &snapshot_output);
294 if (snapshot_output_consumed_len != comm->snapshot_output_len) {
295 ERR("Failed to deserialize snapshot output object: "
296 "consumed-len: %zd, expected-len: %" PRIu32,
297 snapshot_output_consumed_len,
298 comm->snapshot_output_len);
299 goto error;
300 }
301
302 action_status = lttng_action_snapshot_session_set_output(
303 action, snapshot_output);
304 if (action_status != LTTNG_ACTION_STATUS_OK) {
305 goto error;
306 }
307
308 /* Ownership has been transferred to the action. */
309 snapshot_output = NULL;
310 }
311
312 variable_data += comm->snapshot_output_len;
313 consumed_len += comm->snapshot_output_len;
314
315 /* Firing policy. */
316 if (comm->firing_policy_len <= 0) {
317 ERR("Firing policy should be present.");
318 goto error;
319 }
320 {
321 ssize_t firing_policy_consumed_len;
322 struct lttng_payload_view policy_view =
323 lttng_payload_view_from_view(view, consumed_len,
324 comm->firing_policy_len);
325
326 if (!lttng_payload_view_is_valid(&policy_view)) {
327 ERR("Failed to create buffer view for firing policy.");
328 goto error;
329 }
330
331 firing_policy_consumed_len =
332 lttng_firing_policy_create_from_payload(
333 &policy_view, &policy);
334 if (firing_policy_consumed_len < 0) {
335 goto error;
336 }
337
338 if (firing_policy_consumed_len != comm->firing_policy_len) {
339 ERR("Failed to deserialize firing policy object: "
340 "consumed-len: %zd, expected-len: %" PRIu32,
341 firing_policy_consumed_len,
342 comm->firing_policy_len);
343 goto error;
344 }
345
346 status = lttng_action_snapshot_session_set_firing_policy(
347 action, policy);
348 if (status != LTTNG_ACTION_STATUS_OK) {
349 goto error;
350 }
351 }
352
353 variable_data += comm->firing_policy_len;
354 consumed_len += comm->firing_policy_len;
355
356 *p_action = action;
357 action = NULL;
358
359 goto end;
360
361 error:
362 consumed_len = -1;
363
364 end:
365 lttng_firing_policy_destroy(policy);
366 lttng_action_snapshot_session_destroy(action);
367 lttng_snapshot_output_destroy(snapshot_output);
368
369 return consumed_len;
370 }
371
372 struct lttng_action *lttng_action_snapshot_session_create(void)
373 {
374 struct lttng_action *action = NULL;
375 struct lttng_firing_policy *policy = NULL;
376 enum lttng_action_status status;
377
378 /* Create a every N = 1 firing policy. */
379 policy = lttng_firing_policy_every_n_create(1);
380 if (!policy) {
381 goto end;
382 }
383
384 action = zmalloc(sizeof(struct lttng_action_snapshot_session));
385 if (!action) {
386 goto end;
387 }
388
389 lttng_action_init(action, LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
390 lttng_action_snapshot_session_validate,
391 lttng_action_snapshot_session_serialize,
392 lttng_action_snapshot_session_is_equal,
393 lttng_action_snapshot_session_destroy);
394
395 status = lttng_action_snapshot_session_set_firing_policy(
396 action, policy);
397 if (status != LTTNG_ACTION_STATUS_OK) {
398 free(action);
399 action = NULL;
400 goto end;
401 }
402
403 end:
404 lttng_firing_policy_destroy(policy);
405 return action;
406 }
407
408 enum lttng_action_status lttng_action_snapshot_session_set_session_name(
409 struct lttng_action *action, const char *session_name)
410 {
411 struct lttng_action_snapshot_session *action_snapshot_session;
412 enum lttng_action_status status;
413
414 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name ||
415 strlen(session_name) == 0) {
416 status = LTTNG_ACTION_STATUS_INVALID;
417 goto end;
418 }
419
420 action_snapshot_session = action_snapshot_session_from_action(action);
421
422 free(action_snapshot_session->session_name);
423
424 action_snapshot_session->session_name = strdup(session_name);
425 if (!action_snapshot_session->session_name) {
426 status = LTTNG_ACTION_STATUS_ERROR;
427 goto end;
428 }
429
430 status = LTTNG_ACTION_STATUS_OK;
431 end:
432 return status;
433 }
434
435 enum lttng_action_status lttng_action_snapshot_session_get_session_name(
436 const struct lttng_action *action, const char **session_name)
437 {
438 const struct lttng_action_snapshot_session *action_snapshot_session;
439 enum lttng_action_status status;
440
441 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name) {
442 status = LTTNG_ACTION_STATUS_INVALID;
443 goto end;
444 }
445
446 action_snapshot_session = action_snapshot_session_from_action_const(action);
447
448 if (action_snapshot_session->session_name) {
449 *session_name = action_snapshot_session->session_name;
450 status = LTTNG_ACTION_STATUS_OK;
451 } else {
452 status = LTTNG_ACTION_STATUS_UNSET;
453 }
454
455 end:
456
457 return status;
458 }
459
460 enum lttng_action_status lttng_action_snapshot_session_set_output(
461 struct lttng_action *action,
462 struct lttng_snapshot_output *output)
463 {
464 struct lttng_action_snapshot_session *action_snapshot_session;
465 enum lttng_action_status status;
466
467 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !output) {
468 status = LTTNG_ACTION_STATUS_INVALID;
469 goto end;
470 }
471
472 action_snapshot_session = action_snapshot_session_from_action(action);
473
474 lttng_snapshot_output_destroy(action_snapshot_session->output);
475 action_snapshot_session->output = output;
476
477 status = LTTNG_ACTION_STATUS_OK;
478
479 end:
480 return status;
481 }
482
483 enum lttng_action_status lttng_action_snapshot_session_get_output(
484 const struct lttng_action *action,
485 const struct lttng_snapshot_output **output)
486 {
487 const struct lttng_action_snapshot_session *action_snapshot_session;
488 enum lttng_action_status status;
489
490 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action)|| !output) {
491 status = LTTNG_ACTION_STATUS_INVALID;
492 goto end;
493 }
494
495 action_snapshot_session = action_snapshot_session_from_action_const(action);
496
497 if (action_snapshot_session->output) {
498 *output = action_snapshot_session->output;
499 status = LTTNG_ACTION_STATUS_OK;
500 } else {
501 status = LTTNG_ACTION_STATUS_UNSET;
502 }
503
504 end:
505 return status;
506 }
507
508 enum lttng_action_status lttng_action_snapshot_session_set_firing_policy(
509 struct lttng_action *action,
510 const struct lttng_firing_policy *policy)
511 {
512 enum lttng_action_status status;
513 struct lttng_action_snapshot_session *snapshot_session_action;
514 struct lttng_firing_policy *copy = NULL;
515
516 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
517 status = LTTNG_ACTION_STATUS_INVALID;
518 goto end;
519 }
520
521 copy = lttng_firing_policy_copy(policy);
522 if (!copy) {
523 status = LTTNG_ACTION_STATUS_ERROR;
524 goto end;
525 }
526
527 snapshot_session_action = action_snapshot_session_from_action(action);
528
529 /* Free the previous firing policy .*/
530 lttng_firing_policy_destroy(snapshot_session_action->policy);
531
532 /* Assign the policy. */
533 snapshot_session_action->policy = copy;
534 status = LTTNG_ACTION_STATUS_OK;
535 copy = NULL;
536
537 end:
538 lttng_firing_policy_destroy(copy);
539 return status;
540 }
541
542 enum lttng_action_status lttng_action_snapshot_session_get_firing_policy(
543 const struct lttng_action *action,
544 const struct lttng_firing_policy **policy)
545 {
546 enum lttng_action_status status;
547 const struct lttng_action_snapshot_session *snapshot_session_action;
548
549 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
550 status = LTTNG_ACTION_STATUS_INVALID;
551 goto end;
552 }
553
554 snapshot_session_action =
555 action_snapshot_session_from_action_const(action);
556
557 *policy = snapshot_session_action->policy;
558 status = LTTNG_ACTION_STATUS_OK;
559 end:
560 return status;
561 }
This page took 0.06426 seconds and 4 git commands to generate.