1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <libintl.h>
17 #include <sys/uuid.h>
18 #include <sys/debug.h>
19 #include <string.h>
20 #include <inttypes.h>
21
22 #include <libzfs.h>
23 #include <sys/krrp.h>
24 #include "libkrrp.h"
25 #include "libkrrp_impl.h"
26
27 static int
28 krrp_sess_create_common(libkrrp_handle_t *hdl, uuid_t sess_id,
29 const char *sess_kstat_id, const char *auth_digest, boolean_t fake_mode,
30 nvlist_t *params)
31 {
32 int rc;
33 krrp_sess_id_str_t sess_id_str;
34
35 VERIFY(hdl != NULL);
36 VERIFY(sess_kstat_id != NULL);
37
38 libkrrp_reset(hdl);
39
40 uuid_unparse(sess_id, sess_id_str);
41
42 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
43
44 (void) krrp_param_put(KRRP_PARAM_SESS_KSTAT_ID, params,
45 (void *)sess_kstat_id);
46
47 if (auth_digest != NULL) {
48 (void) krrp_param_put(KRRP_PARAM_AUTH_DATA, params,
49 (void *)auth_digest);
50 }
51
52 if (fake_mode)
53 (void) krrp_param_put(KRRP_PARAM_FAKE_MODE, params, NULL);
54
55 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_CREATE, params, NULL);
56
57 return (rc);
58 }
59
60 int
61 krrp_sess_create_sender(libkrrp_handle_t *hdl, uuid_t sess_id,
62 const char *sess_kstat_id, const char *auth_digest, boolean_t fake_mode)
63 {
64 nvlist_t *params = NULL;
65 int rc;
66
67 params = fnvlist_alloc();
68
69 (void) krrp_param_put(KRRP_PARAM_SESS_SENDER, params, NULL);
70
71 rc = krrp_sess_create_common(hdl, sess_id, sess_kstat_id, auth_digest,
72 fake_mode, params);
73
74 fnvlist_free(params);
75 return (rc);
76 }
77
78 int
79 krrp_sess_create_receiver(libkrrp_handle_t *hdl, uuid_t sess_id,
80 const char *sess_kstat_id, const char *auth_digest, boolean_t fake_mode)
81 {
82 nvlist_t *params = NULL;
83 int rc;
84
85 params = fnvlist_alloc();
86
87 rc = krrp_sess_create_common(hdl, sess_id, sess_kstat_id, auth_digest,
88 fake_mode, params);
89
90 fnvlist_free(params);
91 return (rc);
92 }
93
94 int
95 krrp_sess_create_compound(libkrrp_handle_t *hdl, uuid_t sess_id,
96 const char *sess_kstat_id, boolean_t fake_mode)
97 {
98 nvlist_t *params = NULL;
99 int rc;
100
101 params = fnvlist_alloc();
102
103 (void) krrp_param_put(KRRP_PARAM_SESS_COMPOUND, params, NULL);
104
105 rc = krrp_sess_create_common(hdl, sess_id, sess_kstat_id, NULL,
106 fake_mode, params);
107
108 fnvlist_free(params);
109 return (rc);
110 }
111
112 int
113 krrp_sess_destroy(libkrrp_handle_t *hdl, uuid_t sess_id)
114 {
115 nvlist_t *params = NULL;
116 int rc;
117 krrp_sess_id_str_t sess_id_str;
118
119 VERIFY(hdl != NULL);
120
121 libkrrp_reset(hdl);
122
123 uuid_unparse(sess_id, sess_id_str);
124 params = fnvlist_alloc();
125 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
126
127 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_DESTROY, params, NULL);
128
129 fnvlist_free(params);
130 return (rc);
131 }
132
133 int
134 krrp_sess_set_private_data(libkrrp_handle_t *hdl, uuid_t sess_id,
135 nvlist_t *private_data)
136 {
137 nvlist_t *params = NULL;
138 int rc;
139 krrp_sess_id_str_t sess_id_str;
140
141 VERIFY(hdl != NULL);
142 VERIFY(private_data != NULL);
143
144 libkrrp_reset(hdl);
145
146 uuid_unparse(sess_id, sess_id_str);
147 params = fnvlist_alloc();
148 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
149 (void) krrp_param_put(KRRP_PARAM_SESS_PRIVATE_DATA,
150 params, private_data);
151
152 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_SET_PRIVATE_DATA,
153 params, NULL);
154
155 fnvlist_free(params);
156 return (rc);
157 }
158
159 int
160 krrp_sess_get_private_data(libkrrp_handle_t *hdl, uuid_t sess_id,
161 nvlist_t **private_data)
162 {
163 nvlist_t *params = NULL, *result = NULL, *tmp = NULL;
164 int rc;
165 krrp_sess_id_str_t sess_id_str;
166
167 VERIFY(hdl != NULL);
168 VERIFY(private_data != NULL && *private_data == NULL);
169
170 libkrrp_reset(hdl);
171
172 uuid_unparse(sess_id, sess_id_str);
173 params = fnvlist_alloc();
174 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
175
176 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_GET_PRIVATE_DATA,
177 params, &result);
178
179 if (rc != 0)
180 goto fini;
181
182 VERIFY0(krrp_param_get(KRRP_PARAM_SESS_PRIVATE_DATA,
183 result, &tmp));
184
185 *private_data = fnvlist_dup(tmp);
186 fnvlist_free(result);
187
188 fini:
189 fnvlist_free(params);
190 return (rc);
191 }
192
193 int
194 krrp_sess_create_conn(libkrrp_handle_t *hdl, uuid_t sess_id,
195 const char *address, const uint16_t port, const uint32_t conn_timeout)
196 {
197 nvlist_t *params = NULL;
198 int rc;
199 krrp_sess_id_str_t sess_id_str;
200
201 VERIFY(hdl != NULL);
202 VERIFY(address != NULL);
203
204 libkrrp_reset(hdl);
205
206 uuid_unparse(sess_id, sess_id_str);
207 params = fnvlist_alloc();
208
209 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
210 (void) krrp_param_put(KRRP_PARAM_REMOTE_HOST, params, (void *)address);
211 (void) krrp_param_put(KRRP_PARAM_PORT, params, (void *)&port);
212
213 if (conn_timeout != 0) {
214 (void) krrp_param_put(KRRP_PARAM_CONN_TIMEOUT, params,
215 (void *)&conn_timeout);
216 }
217
218 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_CREATE_CONN, params, NULL);
219
220 fnvlist_free(params);
221 return (rc);
222 }
223
224 int
225 krrp_sess_conn_throttle(libkrrp_handle_t *hdl, uuid_t sess_id,
226 const uint32_t limit)
227 {
228 nvlist_t *params = NULL;
229 int rc;
230 krrp_sess_id_str_t sess_id_str;
231
232 VERIFY(hdl != NULL);
233
234 libkrrp_reset(hdl);
235
236 uuid_unparse(sess_id, sess_id_str);
237 params = fnvlist_alloc();
238 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
239 (void) krrp_param_put(KRRP_PARAM_THROTTLE, params, (void *)&limit);
240
241 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_CONN_THROTTLE, params,
242 NULL);
243
244 fnvlist_free(params);
245 return (rc);
246 }
247
248 int
249 krrp_sess_create_pdu_engine(libkrrp_handle_t *hdl, uuid_t sess_id,
250 const int memory_limit, const int dblk_sz, boolean_t use_preallocation)
251 {
252 nvlist_t *params = NULL;
253 int rc;
254 krrp_sess_id_str_t sess_id_str;
255
256 VERIFY(hdl != NULL);
257
258 libkrrp_reset(hdl);
259
260 uuid_unparse(sess_id, sess_id_str);
261 params = fnvlist_alloc();
262 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
263 (void) krrp_param_put(KRRP_PARAM_MAX_MEMORY, params,
264 (void *)&memory_limit);
265 (void) krrp_param_put(KRRP_PARAM_DBLK_DATA_SIZE, params,
266 (void *)&dblk_sz);
267
268 if (use_preallocation) {
269 (void) krrp_param_put(KRRP_PARAM_USE_PREALLOCATION,
270 params, NULL);
271 }
272
273 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_CREATE_PDU_ENGINE, params,
274 NULL);
275
276 fnvlist_free(params);
277 return (rc);
278 }
279
280 static void
281 krrp_sess_create_stream_common(libkrrp_handle_t *hdl, nvlist_t *params,
282 uuid_t sess_id, const char *common_snap,
283 krrp_sess_stream_flags_t krrp_sess_stream_flags, const char *resume_token,
284 uint32_t keep_snaps)
285 {
286 krrp_sess_id_str_t sess_id_str;
287
288 VERIFY(hdl != NULL);
289
290 libkrrp_reset(hdl);
291
292 uuid_unparse(sess_id, sess_id_str);
293
294 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
295
296 /* keep_snaps == UINT32_MAX means "not defined" */
297 if (keep_snaps != UINT32_MAX) {
298 (void) krrp_param_put(KRRP_PARAM_STREAM_KEEP_SNAPS,
299 params, &keep_snaps);
300 }
301
302 if (common_snap != NULL) {
303 (void) krrp_param_put(KRRP_PARAM_COMMON_SNAPSHOT,
304 params, (void *)common_snap);
305 }
306
307 if (resume_token != NULL) {
308 (void) krrp_param_put(KRRP_PARAM_RESUME_TOKEN,
309 params, (void *)resume_token);
310 }
311
312 if (krrp_sess_stream_flags & KRRP_STREAM_ZFS_EMBEDDED) {
313 (void) krrp_param_put(KRRP_PARAM_STREAM_EMBEDDED_BLOCKS,
314 params, NULL);
315 }
316
317 if (krrp_sess_stream_flags & KRRP_STREAM_ZFS_COMPRESSED) {
318 (void) krrp_param_put(KRRP_PARAM_STREAM_COMPRESSED_BLOCKS,
319 params, NULL);
320 }
321
322 if (krrp_sess_stream_flags & KRRP_STREAM_ZFS_LARGE_BLOCKS) {
323 (void) krrp_param_put(KRRP_PARAM_STREAM_LARGE_BLOCKS,
324 params, NULL);
325 }
326
327 if (krrp_sess_stream_flags & KRRP_STREAM_ZFS_CHKSUM) {
328 (void) krrp_param_put(KRRP_PARAM_ENABLE_STREAM_CHKSUM,
329 params, NULL);
330 }
331 }
332
333 int
334 krrp_sess_create_write_stream(libkrrp_handle_t *hdl, uuid_t sess_id,
335 const char *dataset, const char *common_snap,
336 krrp_sess_stream_flags_t krrp_sess_stream_flags, nvlist_t *ignore_props,
337 nvlist_t *replace_props, const char *resume_token, uint32_t keep_snaps)
338 {
339 nvlist_t *replace_props_copy = NULL;
340 nvlist_t *params = NULL;
341 int rc;
342
343 libkrrp_reset(hdl);
344
345 if (replace_props != NULL) {
346 libzfs_handle_t *libzfs_hdl;
347 char errbuf[1024];
348
349 libzfs_hdl = libzfs_init();
350 if (libzfs_hdl == NULL) {
351 libkrrp_error_set(&hdl->libkrrp_error,
352 LIBKRRP_ERRNO_PROPS, ENOMEM, 0);
353 return (-1);
354 }
355
356 replace_props_copy = zfs_valid_proplist(libzfs_hdl,
357 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
358 replace_props, B_FALSE, NULL, NULL, "");
359 if (replace_props_copy == NULL) {
360 libkrrp_error_set(&hdl->libkrrp_error,
361 LIBKRRP_ERRNO_PROPS, EINVAL, 0);
362 (void) snprintf(errbuf, sizeof (errbuf),
363 dgettext(TEXT_DOMAIN, "Failed to validate "
364 "ZFS properties: %s"),
365 libzfs_error_description(libzfs_hdl));
366 libkrrp_set_error_description(hdl, errbuf);
367 }
368
369 libzfs_fini(libzfs_hdl);
370
371 if (replace_props_copy == NULL)
372 return (-1);
373 }
374
375 params = fnvlist_alloc();
376
377 krrp_sess_create_stream_common(hdl, params, sess_id, common_snap,
378 krrp_sess_stream_flags, resume_token, keep_snaps);
379
380 (void) krrp_param_put(KRRP_PARAM_DST_DATASET, params,
381 (void *)dataset);
382
383 if (krrp_sess_stream_flags & KRRP_STREAM_FORCE_RECEIVE)
384 (void) krrp_param_put(KRRP_PARAM_FORCE_RECEIVE, params, NULL);
385
386 if (ignore_props != NULL) {
387 (void) krrp_param_put(KRRP_PARAM_IGNORE_PROPS_LIST, params,
388 ignore_props);
389 }
390
391 if (replace_props_copy != NULL) {
392 (void) krrp_param_put(KRRP_PARAM_REPLACE_PROPS_LIST, params,
393 replace_props_copy);
394 fnvlist_free(replace_props_copy);
395 }
396
397 if (krrp_sess_stream_flags & KRRP_STREAM_DISCARD_HEAD) {
398 /*
399 * Kernel does not yet support this flag
400 */
401 libkrrp_error_set(&hdl->libkrrp_error,
402 LIBKRRP_ERRNO_NOTSUP, 0, 0);
403 rc = -1;
404 goto out;
405 }
406
407 if (krrp_sess_stream_flags & KRRP_STREAM_LEAVE_TAIL) {
408 (void) krrp_param_put(KRRP_PARAM_STREAM_LEAVE_TAIL,
409 params, NULL);
410 }
411
412 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_CREATE_WRITE_STREAM,
413 params, NULL);
414
415 out:
416 fnvlist_free(params);
417
418 return (rc);
419 }
420
421 int
422 krrp_sess_create_read_stream(libkrrp_handle_t *hdl, uuid_t sess_id,
423 const char *dataset, const char *common_snap, const char *src_snap,
424 uint64_t fake_data_sz, krrp_sess_stream_flags_t krrp_sess_stream_flags,
425 const char *resume_token, uint32_t keep_snaps,
426 const char *skip_snaps_mask)
427 {
428 nvlist_t *params = NULL;
429 int rc;
430
431 params = fnvlist_alloc();
432
433 krrp_sess_create_stream_common(hdl, params, sess_id, common_snap,
434 krrp_sess_stream_flags, resume_token, keep_snaps);
435
436 (void) krrp_param_put(KRRP_PARAM_SRC_DATASET, params, (void *)dataset);
437
438 if (fake_data_sz != 0) {
439 (void) krrp_param_put(KRRP_PARAM_FAKE_DATA_SIZE, params,
440 &fake_data_sz);
441 }
442
443 if (src_snap != NULL) {
444 (void) krrp_param_put(KRRP_PARAM_SRC_SNAPSHOT, params,
445 (void *)src_snap);
446 }
447
448 if (krrp_sess_stream_flags & KRRP_STREAM_SEND_RECURSIVE)
449 (void) krrp_param_put(KRRP_PARAM_SEND_RECURSIVE, params, NULL);
450
451 if (krrp_sess_stream_flags & KRRP_STREAM_SEND_PROPERTIES)
452 (void) krrp_param_put(KRRP_PARAM_SEND_PROPERTIES, params, NULL);
453
454 if (krrp_sess_stream_flags & KRRP_STREAM_INCLUDE_ALL_SNAPS) {
455 (void) krrp_param_put(KRRP_PARAM_INCLUDE_ALL_SNAPSHOTS,
456 params, NULL);
457 }
458
459 if (skip_snaps_mask != NULL) {
460 (void) krrp_param_put(KRRP_PARAM_SKIP_SNAPS_MASK,
461 params, (void *)skip_snaps_mask);
462 }
463
464 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_CREATE_READ_STREAM,
465 params, NULL);
466
467 fnvlist_free(params);
468
469 return (rc);
470 }
471
472 int
473 krrp_sess_run(libkrrp_handle_t *hdl, uuid_t sess_id, boolean_t once)
474 {
475 nvlist_t *params = NULL;
476 int rc;
477 krrp_sess_id_str_t sess_id_str;
478
479 VERIFY(hdl != NULL);
480
481 libkrrp_reset(hdl);
482
483 uuid_unparse(sess_id, sess_id_str);
484 params = fnvlist_alloc();
485
486 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
487
488 if (once)
489 (void) krrp_param_put(KRRP_PARAM_ONLY_ONCE, params, NULL);
490
491 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_RUN, params, NULL);
492
493 fnvlist_free(params);
494 return (rc);
495 }
496
497 int
498 krrp_sess_send_stop(libkrrp_handle_t *hdl, uuid_t sess_id)
499 {
500 nvlist_t *params = NULL;
501 int rc;
502 krrp_sess_id_str_t sess_id_str;
503
504 VERIFY(hdl != NULL);
505
506 libkrrp_reset(hdl);
507
508 uuid_unparse(sess_id, sess_id_str);
509 params = fnvlist_alloc();
510 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
511
512 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_SEND_STOP, params, NULL);
513
514 fnvlist_free(params);
515 return (rc);
516 }
517
518 int krrp_sess_status(libkrrp_handle_t *hdl, uuid_t sess_id,
519 libkrrp_sess_status_t *sess_status)
520 {
521 nvlist_t *result = NULL;
522 nvlist_t *params = NULL;
523 char *res_sess_id_str;
524 char *res_sess_kstat_id;
525
526 krrp_sess_id_str_t sess_id_str;
527 int rc = 0;
528
529 VERIFY(hdl != NULL);
530
531 libkrrp_reset(hdl);
532
533 uuid_unparse(sess_id, sess_id_str);
534 params = fnvlist_alloc();
535 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
536
537 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_STATUS, params, &result);
538
539 if (rc != 0) {
540 rc = -1;
541 goto fini;
542 }
543
544 VERIFY0(krrp_param_get(KRRP_PARAM_SESS_ID, result,
545 &res_sess_id_str));
546
547 if (uuid_parse(res_sess_id_str, sess_status->sess_id) != 0) {
548 libkrrp_error_set(&hdl->libkrrp_error,
549 LIBKRRP_ERRNO_SESSID, EINVAL, 0);
550 rc = -1;
551 goto fini;
552 }
553
554 VERIFY0(krrp_param_get(KRRP_PARAM_SESS_STARTED, result,
555 &sess_status->sess_started));
556
557 VERIFY0(krrp_param_get(KRRP_PARAM_SESS_RUNNING, result,
558 &sess_status->sess_running));
559
560 if (krrp_param_exists(KRRP_PARAM_SESS_SENDER, result))
561 sess_status->sess_type = LIBKRRP_SESS_TYPE_SENDER;
562 else if (krrp_param_exists(KRRP_PARAM_SESS_COMPOUND, result))
563 sess_status->sess_type = LIBKRRP_SESS_TYPE_COMPOUND;
564 else
565 sess_status->sess_type = LIBKRRP_SESS_TYPE_RECEIVER;
566
567 VERIFY0(krrp_param_get(KRRP_PARAM_SESS_KSTAT_ID, result,
568 &res_sess_kstat_id));
569
570 (void) strlcpy(sess_status->sess_kstat_id, res_sess_kstat_id,
571 KRRP_KSTAT_ID_STRING_LENGTH);
572
573 if (krrp_param_exists(KRRP_PARAM_ERROR_CODE, result)) {
574 rc = libkrrp_error_from_nvl(result,
575 &sess_status->libkrrp_error);
576 ASSERT0(rc);
577 } else {
578 sess_status->libkrrp_error.libkrrp_errno = 0;
579 }
580
581 fini:
582 fnvlist_free(params);
583
584 if (result != NULL)
585 fnvlist_free(result);
586
587 return (rc);
588 }
589
590 int
591 krrp_sess_get_conn_info(libkrrp_handle_t *hdl, uuid_t sess_id,
592 libkrrp_sess_conn_info_t *sess_conn_info)
593 {
594 nvlist_t *result = NULL;
595 nvlist_t *params = NULL;
596 krrp_sess_id_str_t sess_id_str;
597 int rc = 0;
598
599 VERIFY(hdl != NULL);
600 VERIFY(sess_conn_info != NULL);
601
602 libkrrp_reset(hdl);
603
604 uuid_unparse(sess_id, sess_id_str);
605 params = fnvlist_alloc();
606 (void) krrp_param_put(KRRP_PARAM_SESS_ID, params, sess_id_str);
607
608 rc = krrp_ioctl_perform(hdl, KRRP_IOCTL_SESS_GET_CONN_INFO, params, &result);
609 if (rc != 0)
610 goto fini;
611
612 VERIFY0(krrp_param_get(KRRP_PARAM_DBLK_DATA_SIZE, result,
613 &sess_conn_info->blk_sz));
614
615 fini:
616 fnvlist_free(params);
617
618 fnvlist_free(result);
619
620 return (rc);
621 }