xref: /illumos-gate/usr/src/common/svc/repcache_protocol.h (revision e38a713ad4e0a9c42f8cccd9350412b2c6ccccdb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifndef	_REPCACHE_PROTOCOL_H
28 #define	_REPCACHE_PROTOCOL_H
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 /*
33  * The Repository Cache Protocol
34  * -----------------------------
35  *
36  * 1. Introduction
37  * ---------------
38  * This header file defines the private protocols between libscf(3lib) and
39  * svc.configd(1m).  There are two separate protocols:
40  *
41  * 1.	The 'global' protocol, accessible via an fattach(3C)ed door located
42  *	at REPOSITORY_DOOR_NAME.
43  *
44  * 2.	The 'client' protocol, accessible through a door created using the
45  *	global protocol, which allows access to the repository.
46  *
47  * 1.1 Design restrictions
48  * -----------------------
49  * A basic constraint of the door IPC mechanism is that there is no reliable
50  * delivery.  In particular:
51  *
52  * 1.	If libscf(3lib) recieves an EINTR from door_call(), it doesn't know
53  *      whether or not the server recieved (and is processing) its request.
54  *
55  * 2.	When svc.configd(1M) calls door_return(), the client may have already
56  *	received an EINTR, aborting its door_call().  In this case, the
57  *	returned values are dropped on the floor.
58  *
59  * The practical upshot of all of this is simple:
60  *
61  *	Every individual protocol action must be idempotent.
62  *
63  * That is, a client must be able to retry any single request multiple times,
64  * and get the correct results.
65  *
66  * 1.2. Protocol shorthand
67  * -----------------------
68  * We represent by "REQUEST(arg1, arg2) -> result, res1, [desc]" a request code
69  * of REP_PROTOCOL_REQUEST (or REPOSITORY_DOOR_REQUEST), which takes two
70  * additional arguments, arg1 and arg2, and returns a result code, res1, and
71  * a file descriptor desc.
72  *
73  * If an error occurs, the server will usually only send the result code. (a
74  * short return)
75  *
76  * Inside the protocol destription, <foo> indicates the type foo indicates.
77  *
78  * 2. The Global protocol
79  * ----------------------
80  * Everything starting with "REPOSITORY_DOOR" or "repository_door" belongs
81  * to the global protocol.
82  *
83  * 2.1. Global requests
84  * --------------------
85  *
86  * REQUEST_CONNECT(rdr_flags, ...) -> result, [new_door]
87  *	Request a new Client door.  rdr_flags determines attributes of the
88  *	connection:
89  *
90  *	    FLAG_DEBUG
91  *		Sets connection debugging flags to those in rdr_debug.
92  *
93  *	The new door is returned with DOOR_RELEASE set, so if the client does
94  *	not recieve the response, the new door will recieve an unref
95  *	notification.  This makes this request idempotent.
96  *
97  * 2.2. Global reponse codes
98  * -------------------------
99  * GLXXX: This needs to be thought through.
100  *
101  * SUCCESS
102  * FAIL_BAD_REQUEST
103  * FAIL_VERSION_MISMATCH
104  * FAIL_BAD_FLAG
105  * FAIL_BAD_USER
106  * FAIL_NO_RESOURCES
107  *
108  * 3. The Client protocol
109  * ----------------------
110  * Everything starting with "REP_PROTOCOL" or "rep_protocol" belongs to the
111  * client protocol.
112  *
113  * 3.1. Techniques used
114  * --------------------
115  * 3.1.1. Client-controlled identifiers
116  *
117  * An idiom the protocol uses to lower the number of round trips is
118  * client-controlled identifiers.  The basic idea is this:  whenever a
119  * client wants to set up and use a piece of server state, he picks an
120  * integer *which he knows is not in use* to identify it.  The server then
121  * maintains per-client, per-resource id->resource maps.  This has a number
122  * of advantages:
123  *
124  * 1.	Since the client allocates the identifiers, we don't need to do
125  *	a round-trip just to allocate a number.
126  *
127  * 2.	Since it is the client's job to make sure identifiers don't collide,
128  *	idempotency for setup (destroy) are simple:  If the identifier
129  *	already exists (does not exist), we just return success.
130  *
131  * 3.	Since the identifiers are per-client, the design automatically
132  *	precludes clients being able to manipulate other client's state.
133  *
134  * 3.1.2 Sequence numbers
135  *
136  * A standard way of gaining idempotency is introducing sequence numbers.
137  * These are simply integers which get incremented at points in the protocol,
138  * and make sure the client and server are in sync.
139  *
140  * In this protocol, we use sequence numbers for requests (like ITER_READ)
141  * which are repeated, returning different data each time.  Since requests
142  * can also be repeated due to unreliable dispatch, the client increments
143  * the sequence number after every successful request.  This allows the server
144  * to differentiate the two cases. (note that this means that failing
145  * requests have no side effects and are repeatable)
146  *
147  * 3.2. Client abstractions
148  * ------------------------
149  * 3.2.1 Entities
150  *
151  * An "entity" is a typed register which the client can manipulate.
152  * Entities are named in the protocol by client-controlled identifiers.
153  * They have a fixed type for their entire lifetime, and may be in one
154  * of two states:
155  *
156  * valid
157  *	The entity has a valid value, and may be read from.  This state
158  *	is reached by a successful write to the entity by some protocol
159  *	step.
160  *
161  * invalid
162  *	The entity does not contain a valid value.  There are a number
163  *	of ways to reach this state:
164  *
165  *	1.  The entity was just created.
166  *	2.  The underlying object that this entity refers to was destroyed.
167  *	3.  A protocol request which would have modified this entity
168  *	    failed.
169  *
170  * An entity is an element in the tree of repository data.  Every entity
171  * (except for the most distant SCOPE) has exactly one parent.  Entities
172  * can have multiple children of different types, restricted by its base
173  * type.
174  *
175  * The ENTITY_GET call is used to get the root of the tree (the most local
176  * scope)
177  *
178  * 3.2.2. The entity tree
179  * ----------------------
180  * The structure of a scope is as follows:
181  *
182  *	 _______
183  *	| SCOPE |
184  *	|_______|
185  *	    \ .
186  *	     \ .
187  *	      \_________
188  *	      | SERVICE |
189  *	      |_________|
190  *		/.    \ .
191  *	       /.      \ .
192  *	  ____/		\__________
193  *	 | PG |		| INSTANCE |
194  *	 |____|		|__________|
195  *			  /.	 \ .
196  *			 /.	  \ .
197  *		    ____/	   \__________
198  *		   | PG |	   | SNAPSHOT |
199  *		   |____|	   |__________|
200  *					\ .
201  *					 \ .
202  *					  \___________
203  *					  | SNAPLEVEL |
204  *					  |___________|
205  *					     /.
206  *					    /.
207  *				       ____/
208  *				      | PG |
209  *				      |____|
210  *
211  * Where the dots indicate an arbitrary number (including 0) of children.
212  *
213  * For a given scope, the next scope (in the sense of distance) is its
214  * TYPE_SCOPE parent.  The furthest out scope has no parent.
215  *
216  * 3.2.2 Iterators
217  *
218  * GLXXX
219  *
220  * 3.3. Client requests
221  * --------------------
222  *
223  * CLOSE() -> result
224  *	Closes the connection, revoking the door.  After this call completes,
225  *	no further calls will succeed.
226  *
227  * ENTITY_SETUP(entity_id, type) -> result
228  *	Sets up an entity, identified by entity_id, to identify a single
229  *	<type>.  <type> may not be TYPE_NONE.
230  *
231  * ENTITY_NAME(entity_id, name_type) -> result, name
232  *	Returns the name of entity_id.  name_type determines which type of
233  *	name to get.
234  *
235  * ENTITY_PARENT_TYPE(entity_id) -> result, parent_type
236  *	Retrieves the type of entity_id's parent
237  *
238  * ENTITY_GET_CHILD(entity_id, child_id, name) -> result
239  *	Puts entity_id's child (of child_id's type) named 'name' into child_id.
240  *
241  * ENTITY_GET_PARENT(entity_id, out_id) -> result
242  *	Puts entity_id's parent into out_id.
243  *
244  * ENTITY_GET(entity_id, number) -> result
245  *	Makes entity_id point to a particular object.  If any error
246  *	occurs, dest_id will be invalid.
247  *
248  * ENTITY_UPDATE(entity_id, changeid) -> result
249  *	Updates the entity to pick up any new changes.
250  *
251  * ENTITY_CREATE_CHILD(entity_id, type, name, child_id, changeid) -> result
252  *	Attaches the object of type /type/ in child_id as the child of
253  *	entity_id named 'name'.
254  *
255  * ENTITY_CREATE_PG(entity_id, name, type, flags, child_id, changeid) -> result
256  *	Creates a property group child of entity_id named 'name', type 'type'
257  *	and flags 'flags', and puts the resulting object in child_id.
258  *
259  * ENTITY_DELETE(entity_id, changeid) -> result
260  *	Deletes the entity represented by entity_id.
261  *
262  * ENTITY_RESET(entity_id) -> result
263  *	Resets the entity.
264  *
265  * ENTITY_TEARDOWN(entity_id) -> result
266  *	Destroys the entity entity_id.
267  *
268  * ITER_SETUP(iter_id) -> result
269  *	Sets up an iterator id.
270  *
271  * ITER_START(iter_id, entity_id, itertype, flags, pattern) -> result
272  *	Sets up an iterator, identified by iter_id, which will iterate the
273  *	<itertype> children of entity_id whose names match 'pattern',
274  *	with the matching controlled by flags.  Initializing an iterator
275  *	counts as the first sequence number (1).
276  *
277  * ITER_READ(iter_id, sequence, entity_id) -> result
278  *	Retrieves the next element of iterator iter_id.  Sequence starts at 2,
279  *	and is incremented by the client after each successful iteration.
280  *	The result is written to entity_id, which must be of the same type
281  *	as the iterator result.  The iterator must not be iterating values.
282  *
283  * ITER_READ_VALUE(iter_id, sequence) -> result, type, value
284  *	Retrieves the next value for iterator iter_id.  Sequence starts at 2,
285  *	and is incremented by the client after each successful iteration.
286  *	The iterator must be iterating a property's values.
287  *
288  * ITER_RESET(iter_id) -> result
289  *	Throws away any accumulated state.
290  *
291  * ITER_TEARDOWN(iter_id) -> result
292  *	Destroys the iterator iter_id.
293  *
294  * NEXT_SNAPLEVEL(entity_src, entity_dst) -> result
295  *	If entity_src is a snapshot, set entity_dst to the first snaplevel
296  *	in it.  If entity_src is a snaplevel, set entity_dst to the next
297  *	snaplevel, or fail if there isn't one.
298  *
299  * SNAPSHOT_TAKE(entity_id, name, dest_id, flags) -> result
300  *	Takes a snapshot of entity_id, creating snaplevels for the instance and
301  *	its parent service.  If flags is REP_SNAPSHOT_NEW, a new snapshot named
302  *	'name' is created as a child of entity_id, dest_id is pointed to it,
303  *	and the new snaplevels are attached to it.  If flags is
304  *	REP_SNAPSHOT_ATTACH, name must be empty, and the new snaplevels are
305  *	attached to the snapshot dest_id points to.
306  *
307  * SNAPSHOT_TAKE_NAMED(entity_id, instname, svcname, name, dest_id) -> result
308  *	Like SNAPSHOT_TAKE, but always acts as if REP_SNAPSHOT_NEW is
309  *	specified, and instname and svcname override the actual service and
310  *	instance names, respectively, written into the snaplevels.
311  *
312  *	Note that this is only useful for writing snapshots which will later
313  *	be transferred to another instance (svc:/svcname:instname/)
314  *
315  * SNAPSHOT_ATTACH(source_id, dest_id) -> result
316  *	The snaplevels attached to the snapshot referenced by source_id are
317  *	attached to the snapshot dest_id is pointed at.
318  *
319  * PROPERTY_GET_TYPE(entity_id) -> result, value type
320  *	Finds the value type of entity_id, which must be a property.
321  *
322  * PROPERTY_GET_VALUE(entity_id) -> result, type, value
323  *	If the property contains a single value, returns it and its type.
324  *
325  * PROPERTYGRP_SETUP_WAIT(entity_id) -> result, [pipe fd]
326  *	Sets up a notification for changes to the object entity_id currently
327  *	references.  On success, returns one side of a pipe -- when there
328  *	has been a change (or the daemon dies), the other end of the pipe will
329  *	be closed.
330  *
331  *	Only one of these can be set up per client -- attempts to set up more
332  *	than one will cause the previous one to get closed.
333  *
334  * PROPERTYGRP_TX_START(entity_id_tx, entity_id) -> result
335  *	Makes entity_id_tx point to the same property group as entity_id,
336  *	then attempts to set up entity_id_tx as a transaction on that group.
337  *	entity_id and entity_id_tx must be distinct.  On failure, entity_id_tx
338  *	is reset.
339  *
340  * PROPERTYGRP_TX_COMMIT(entity_id, data) -> result
341  *	Gives the actual steps to follow, and attempts to commit them.
342  *
343  * CLIENT_ADD_NOTIFY(type, pattern) -> result
344  *	Adds a new property group name or type pattern to the notify list
345  *	(see CLIENT_WAIT).  If successful, takes effect immediately.
346  *
347  * CLIENT_WAIT(entity_id) -> result, fmri
348  *	Waits for a change to a propertygroup that matches the patterns
349  *	set up using CLIENT_ADD_NOTIFY, and puts the resultant propertygroup
350  *	in entity_id.  Note that if an error occurs, you can loose
351  *	notifications.  Either entity_id is set to a changed propertygroup,
352  *	or fmri is a non-zero-length string identifying a deleted thing.
353  *
354  * BACKUP(name) -> result
355  *	Backs up the persistant repository with a particular name.
356  *
357  * SET_ANNOTATION(operation, file)
358  *	Set up a security audit annotation event.  operation is the name of
359  *	the operation that is being annotated, and file is the file being
360  *	processed.  This will be used to mark operations which comprise
361  *	multiple primitive operations such as svccfg import.
362  */
363 
364 #include <door.h>
365 #include <stddef.h>
366 #include <sys/sysmacros.h>
367 
368 #ifdef	__cplusplus
369 extern "C" {
370 #endif
371 
372 /*
373  * svc.configd initial protocol details
374  */
375 #define	REPOSITORY_DOOR_BASEVER	(('R' << 24) | ('e' << 16) | ('p' << 8))
376 #define	REPOSITORY_DOOR_NAME	"/etc/svc/volatile/repository_door"
377 #define	REPOSITORY_DOOR_COOKIE	((void *)REPOSITORY_DOOR_BASEVER)
378 
379 #define	REPOSITORY_BOOT_BACKUP	((const char *)"boot")
380 
381 /*
382  * This value should be incremented any time the protocol changes.  When in
383  * doubt, bump it.
384  */
385 #define	REPOSITORY_DOOR_VERSION			(20 + REPOSITORY_DOOR_BASEVER)
386 
387 /*
388  * flags for rdr_flags
389  */
390 #define	REPOSITORY_DOOR_FLAG_DEBUG		0x00000001	/* rdr_debug */
391 
392 #define	REPOSITORY_DOOR_FLAG_ALL		0x00000001	/* all flags */
393 
394 /*
395  * Request IDs
396  */
397 enum repository_door_requestid {
398 	REPOSITORY_DOOR_REQUEST_CONNECT = (('M' << 8) | 1)
399 };
400 
401 enum repository_door_statusid {
402 	REPOSITORY_DOOR_SUCCESS			= 0,
403 	REPOSITORY_DOOR_FAIL_BAD_REQUEST	= 1,
404 	REPOSITORY_DOOR_FAIL_VERSION_MISMATCH	= 2,
405 	REPOSITORY_DOOR_FAIL_BAD_FLAG		= 3,
406 	REPOSITORY_DOOR_FAIL_NO_RESOURCES	= 4,
407 	REPOSITORY_DOOR_FAIL_PERMISSION_DENIED	= 5
408 };
409 
410 /*
411  * You may only add elements to the end of this structure.
412  */
413 typedef struct repository_door_request {
414 	uint32_t rdr_version;			/* must be first element */
415 	enum repository_door_requestid rdr_request;
416 	uint32_t rdr_flags;
417 	uint32_t rdr_debug;
418 } repository_door_request_t;
419 
420 typedef struct repository_door_response {
421 	enum repository_door_statusid rdr_status;
422 } repository_door_response_t;
423 
424 /*
425  * Client interface.  Used on doors returned by REQUEST_CONNECT
426  */
427 
428 #define	REP_PROTOCOL_NAME_LEN		120	/* maximum name length */
429 #define	REP_PROTOCOL_VALUE_LEN		4096	/* maximum value length */
430 
431 #define	REP_PROTOCOL_FMRI_LEN		(6 * REP_PROTOCOL_NAME_LEN)
432 
433 #define	REP_PROTOCOL_BASE		('C' << 8)
434 
435 /*
436  * Request codes
437  */
438 enum rep_protocol_requestid {
439 	REP_PROTOCOL_CLOSE		= REP_PROTOCOL_BASE,
440 
441 	REP_PROTOCOL_ENTITY_SETUP,
442 	REP_PROTOCOL_ENTITY_NAME,
443 	REP_PROTOCOL_ENTITY_PARENT_TYPE,
444 	REP_PROTOCOL_ENTITY_GET_CHILD,
445 	REP_PROTOCOL_ENTITY_GET_PARENT,
446 	REP_PROTOCOL_ENTITY_GET,
447 	REP_PROTOCOL_ENTITY_UPDATE,
448 	REP_PROTOCOL_ENTITY_CREATE_CHILD,
449 	REP_PROTOCOL_ENTITY_CREATE_PG,
450 	REP_PROTOCOL_ENTITY_DELETE,
451 	REP_PROTOCOL_ENTITY_RESET,
452 	REP_PROTOCOL_ENTITY_TEARDOWN,
453 
454 	REP_PROTOCOL_ITER_SETUP,
455 	REP_PROTOCOL_ITER_START,
456 	REP_PROTOCOL_ITER_READ,
457 	REP_PROTOCOL_ITER_READ_VALUE,
458 	REP_PROTOCOL_ITER_RESET,
459 	REP_PROTOCOL_ITER_TEARDOWN,
460 
461 	REP_PROTOCOL_NEXT_SNAPLEVEL,
462 
463 	REP_PROTOCOL_SNAPSHOT_TAKE,
464 	REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,
465 	REP_PROTOCOL_SNAPSHOT_ATTACH,
466 
467 	REP_PROTOCOL_PROPERTY_GET_TYPE,
468 	REP_PROTOCOL_PROPERTY_GET_VALUE,
469 
470 	REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT,
471 	REP_PROTOCOL_PROPERTYGRP_TX_START,
472 	REP_PROTOCOL_PROPERTYGRP_TX_COMMIT,
473 
474 	REP_PROTOCOL_CLIENT_ADD_NOTIFY,
475 	REP_PROTOCOL_CLIENT_WAIT,
476 
477 	REP_PROTOCOL_BACKUP,
478 
479 	REP_PROTOCOL_SET_AUDIT_ANNOTATION,
480 
481 	REP_PROTOCOL_MAX_REQUEST
482 };
483 
484 /*
485  * Response codes.  These are returned to the client, and the errors are
486  * translated into scf_error_t's by libscf (see proto_error()).
487  */
488 typedef int32_t rep_protocol_responseid_t;
489 enum rep_protocol_responseid {
490 	REP_PROTOCOL_SUCCESS =			0,
491 	/* iterators: No more values. */
492 	REP_PROTOCOL_DONE =			1,
493 
494 	/* Request from client was malformed. */
495 	REP_PROTOCOL_FAIL_BAD_REQUEST =		-1,
496 	/* Prerequisite call has not been made. */
497 	REP_PROTOCOL_FAIL_MISORDERED =		-2,
498 	/* Register for ID has not been created. */
499 	REP_PROTOCOL_FAIL_UNKNOWN_ID =		-3,
500 	/* Out of memory or other resource. */
501 	REP_PROTOCOL_FAIL_NO_RESOURCES =	-4,
502 	/* Type argument is invalid. */
503 	REP_PROTOCOL_FAIL_INVALID_TYPE =	-5,
504 	/* Requested object does not exist. */
505 	REP_PROTOCOL_FAIL_NOT_FOUND =		-6,
506 	/* Register for given ID does not point to an object. */
507 	REP_PROTOCOL_FAIL_NOT_SET =		-7,
508 
509 	/* Requested name is longer than supplied buffer. */
510 	REP_PROTOCOL_FAIL_TRUNCATED =		-8,
511 	/* Operation requires different type. */
512 	REP_PROTOCOL_FAIL_TYPE_MISMATCH =	-9,
513 
514 	/* Changeable object has been changed since last update. */
515 	REP_PROTOCOL_FAIL_NOT_LATEST =		-10,
516 	/* Creation failed because object with given name exists. */
517 	REP_PROTOCOL_FAIL_EXISTS =		-11,
518 	/* Transaction is invalid. */
519 	REP_PROTOCOL_FAIL_BAD_TX =		-12,
520 	/* Operation is not applicable to indicated object. */
521 	REP_PROTOCOL_FAIL_NOT_APPLICABLE =	-13,
522 	/* Two IDs for operation were unexpectedly equal. */
523 	REP_PROTOCOL_FAIL_DUPLICATE_ID =	-14,
524 
525 	/* Permission denied. */
526 	REP_PROTOCOL_FAIL_PERMISSION_DENIED =	-15,
527 	/* Backend does not exist or otherwise refused access. */
528 	REP_PROTOCOL_FAIL_BACKEND_ACCESS =	-16,
529 	/* Backend is read-only. */
530 	REP_PROTOCOL_FAIL_BACKEND_READONLY =	-17,
531 
532 	/* Object has been deleted. */
533 	REP_PROTOCOL_FAIL_DELETED =		-18,
534 
535 	REP_PROTOCOL_FAIL_UNKNOWN =		-0xfd
536 };
537 
538 /*
539  * Types
540  */
541 typedef enum rep_protocol_entity {
542 	REP_PROTOCOL_ENTITY_NONE,
543 	REP_PROTOCOL_ENTITY_SCOPE,
544 	REP_PROTOCOL_ENTITY_SERVICE,
545 	REP_PROTOCOL_ENTITY_INSTANCE,
546 	REP_PROTOCOL_ENTITY_SNAPSHOT,
547 	REP_PROTOCOL_ENTITY_SNAPLEVEL,
548 	REP_PROTOCOL_ENTITY_PROPERTYGRP,
549 	REP_PROTOCOL_ENTITY_CPROPERTYGRP,	/* "composed" property group */
550 	REP_PROTOCOL_ENTITY_PROPERTY,
551 	REP_PROTOCOL_ENTITY_VALUE,
552 
553 	REP_PROTOCOL_ENTITY_MAX
554 } rep_protocol_entity_t;
555 
556 typedef enum rep_protocol_value_type {
557 	REP_PROTOCOL_TYPE_INVALID	= '\0',
558 	REP_PROTOCOL_TYPE_BOOLEAN	= 'b',
559 	REP_PROTOCOL_TYPE_COUNT		= 'c',
560 	REP_PROTOCOL_TYPE_INTEGER	= 'i',
561 	REP_PROTOCOL_TYPE_TIME		= 't',
562 	REP_PROTOCOL_TYPE_STRING	= 's',
563 	REP_PROTOCOL_TYPE_OPAQUE	= 'o',
564 
565 	REP_PROTOCOL_SUBTYPE_USTRING	= REP_PROTOCOL_TYPE_STRING|('u' << 8),
566 	REP_PROTOCOL_SUBTYPE_URI	= REP_PROTOCOL_TYPE_STRING|('U' << 8),
567 	REP_PROTOCOL_SUBTYPE_FMRI	= REP_PROTOCOL_TYPE_STRING|('f' << 8),
568 
569 	REP_PROTOCOL_SUBTYPE_HOST	= REP_PROTOCOL_TYPE_STRING|('h' << 8),
570 	REP_PROTOCOL_SUBTYPE_HOSTNAME	= REP_PROTOCOL_TYPE_STRING|('N' << 8),
571 	REP_PROTOCOL_SUBTYPE_NETADDR_V4	= REP_PROTOCOL_TYPE_STRING|('4' << 8),
572 	REP_PROTOCOL_SUBTYPE_NETADDR_V6	= REP_PROTOCOL_TYPE_STRING|('6' << 8)
573 } rep_protocol_value_type_t;
574 
575 
576 #define	REP_PROTOCOL_BASE_TYPE(t)	((t) & 0x00ff)
577 #define	REP_PROTOCOL_SUBTYPE(t)		(((t) & 0xff00) >> 8)
578 
579 /*
580  * Request structures
581  */
582 typedef struct rep_protocol_request {
583 	enum rep_protocol_requestid rpr_request;
584 } rep_protocol_request_t;
585 
586 struct rep_protocol_iter_request {
587 	enum rep_protocol_requestid rpr_request;
588 	uint32_t rpr_iterid;
589 };
590 
591 struct rep_protocol_iter_start {
592 	enum rep_protocol_requestid rpr_request;	/* ITER_START */
593 	uint32_t rpr_iterid;
594 
595 	uint32_t rpr_entity;
596 	uint32_t rpr_itertype;
597 	uint32_t rpr_flags;
598 	char	rpr_pattern[REP_PROTOCOL_NAME_LEN];
599 };
600 #define	RP_ITER_START_ALL	0x00000001	/* ignore pattern, match all */
601 #define	RP_ITER_START_EXACT	0x00000002	/* exact match with pattern */
602 #define	RP_ITER_START_PGTYPE	0x00000003	/* exact match pg type */
603 #define	RP_ITER_START_FILT_MASK	0x00000003
604 #define	RP_ITER_START_COMPOSED	0x00000004	/* composed */
605 
606 struct rep_protocol_iter_read {
607 	enum rep_protocol_requestid rpr_request;	/* ITER_READ */
608 	uint32_t rpr_iterid;
609 	uint32_t rpr_sequence;		/* client increments upon success */
610 	uint32_t rpr_entityid;		/* entity to write result to */
611 };
612 
613 struct rep_protocol_iter_read_value {
614 	enum rep_protocol_requestid rpr_request;	/* ITER_READ_VALUE */
615 	uint32_t rpr_iterid;
616 	uint32_t rpr_sequence;		/* client increments upon success */
617 };
618 
619 struct rep_protocol_entity_setup {
620 	enum rep_protocol_requestid rpr_request;	/* ENTITY_SETUP */
621 	uint32_t rpr_entityid;
622 	uint32_t rpr_entitytype;
623 };
624 
625 struct rep_protocol_entity_name {
626 	enum rep_protocol_requestid rpr_request;	/* ENTITY_NAME */
627 	uint32_t rpr_entityid;
628 	uint32_t rpr_answertype;
629 };
630 #define	RP_ENTITY_NAME_NAME			0
631 #define	RP_ENTITY_NAME_PGTYPE			1
632 #define	RP_ENTITY_NAME_PGFLAGS			2
633 #define	RP_ENTITY_NAME_SNAPLEVEL_SCOPE		3
634 #define	RP_ENTITY_NAME_SNAPLEVEL_SERVICE	4
635 #define	RP_ENTITY_NAME_SNAPLEVEL_INSTANCE	5
636 #define	RP_ENTITY_NAME_PGREADPROT		6
637 
638 struct rep_protocol_entity_update {
639 	enum rep_protocol_requestid rpr_request;	/* ENTITY_UPDATE */
640 	uint32_t rpr_entityid;
641 	uint32_t rpr_changeid;
642 };
643 
644 struct rep_protocol_entity_parent_type {
645 	enum rep_protocol_requestid rpr_request;	/* ENTITY_PARENT_TYPE */
646 	uint32_t rpr_entityid;
647 };
648 
649 struct rep_protocol_entity_parent {
650 	enum rep_protocol_requestid rpr_request;	/* ENTITY_GET_PARENT */
651 	uint32_t rpr_entityid;
652 	uint32_t rpr_outid;
653 };
654 
655 struct rep_protocol_entity_get {
656 	enum rep_protocol_requestid rpr_request;	/* ENTITY_SET */
657 	uint32_t rpr_entityid;
658 	uint32_t rpr_object;
659 };
660 #define	RP_ENTITY_GET_INVALIDATE	1
661 #define	RP_ENTITY_GET_MOST_LOCAL_SCOPE	2
662 
663 struct rep_protocol_entity_create_child {
664 	enum rep_protocol_requestid rpr_request; /* ENTITY_CREATE_CHILD */
665 	uint32_t rpr_entityid;
666 	uint32_t rpr_childtype;
667 	uint32_t rpr_childid;
668 	uint32_t rpr_changeid;
669 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
670 };
671 
672 struct rep_protocol_entity_create_pg {
673 	enum rep_protocol_requestid rpr_request; /* ENTITY_CREATE_PG */
674 	uint32_t rpr_entityid;
675 	uint32_t rpr_childtype;
676 	uint32_t rpr_childid;
677 	uint32_t rpr_changeid;
678 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
679 	char	rpr_type[REP_PROTOCOL_NAME_LEN];
680 	uint32_t rpr_flags;
681 };
682 
683 struct rep_protocol_entity_get_child {
684 	enum rep_protocol_requestid rpr_request;	/* ENTITY_GET_CHILD */
685 	uint32_t rpr_entityid;
686 	uint32_t rpr_childid;
687 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
688 };
689 
690 struct rep_protocol_entity_delete {
691 	enum rep_protocol_requestid rpr_request; /* ENTITY_DELETE_CHILD */
692 	uint32_t rpr_entityid;
693 	uint32_t rpr_changeid;
694 };
695 
696 struct rep_protocol_entity_reset {
697 	enum rep_protocol_requestid rpr_request;	/* ENTITY_NAME */
698 	uint32_t rpr_entityid;
699 };
700 
701 struct rep_protocol_entity_request {
702 	enum rep_protocol_requestid rpr_request;	/* ENTITY_NAME */
703 	uint32_t rpr_entityid;
704 };
705 
706 struct rep_protocol_entity_teardown {
707 	enum rep_protocol_requestid rpr_request;	/* ENTITY_TEARDOWN */
708 	uint32_t rpr_entityid;
709 };
710 
711 struct rep_protocol_entity_pair {
712 	enum rep_protocol_requestid rpr_request;	/* NEXT_SNAPLEVEL */
713 	uint32_t rpr_entity_src;
714 	uint32_t rpr_entity_dst;
715 };
716 
717 struct rep_protocol_transaction_start {
718 	enum rep_protocol_requestid rpr_request;	/* TX_SETUP */
719 	uint32_t rpr_entityid_tx;		/* property group tx entity */
720 	uint32_t rpr_entityid;			/* property group entity */
721 };
722 
723 struct rep_protocol_transaction_commit {
724 	enum rep_protocol_requestid rpr_request; /* TX_COMMIT */
725 	uint32_t rpr_entityid;
726 	uint32_t rpr_size;			/* size of entire structure */
727 	uint8_t rpr_cmd[1];
728 };
729 
730 #define	REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(sz) \
731 	    (offsetof(struct rep_protocol_transaction_commit, rpr_cmd[sz]))
732 
733 #define	REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE \
734 	    REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(0)
735 
736 enum rep_protocol_transaction_action {
737 	REP_PROTOCOL_TX_ENTRY_INVALID,	/* N/A */
738 	REP_PROTOCOL_TX_ENTRY_NEW,	/* new property */
739 	REP_PROTOCOL_TX_ENTRY_CLEAR,	/* clear old property */
740 	REP_PROTOCOL_TX_ENTRY_REPLACE,	/* change type of old property */
741 	REP_PROTOCOL_TX_ENTRY_DELETE	/* delete property (no values) */
742 };
743 
744 struct rep_protocol_transaction_cmd {
745 	enum	rep_protocol_transaction_action rptc_action;
746 	uint32_t rptc_type;
747 	uint32_t rptc_size;		/* size of entire structure */
748 	uint32_t rptc_name_len;
749 	uint8_t	rptc_data[1];
750 };
751 
752 #define	REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz) \
753 	    (offsetof(struct rep_protocol_transaction_cmd, rptc_data[sz]))
754 
755 #define	REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE \
756 	    REP_PROTOCOL_TRANSACTION_CMD_SIZE(0)
757 
758 #define	TX_SIZE(x)	P2ROUNDUP((x), sizeof (uint32_t))
759 
760 struct rep_protocol_transaction_request {
761 	enum rep_protocol_requestid rpr_request; /* SETUP, ABORT or TEARDOWN */
762 	uint32_t rpr_txid;
763 };
764 
765 struct rep_protocol_property_request {
766 	enum rep_protocol_requestid rpr_request;
767 	uint32_t rpr_entityid;
768 };
769 
770 struct rep_protocol_propertygrp_request {
771 	enum rep_protocol_requestid rpr_request;
772 	uint32_t rpr_entityid;
773 };
774 
775 struct rep_protocol_notify_request {
776 	enum rep_protocol_requestid rpr_request;
777 	uint32_t rpr_type;
778 	char	rpr_pattern[REP_PROTOCOL_NAME_LEN];
779 };
780 #define	REP_PROTOCOL_NOTIFY_PGNAME 1
781 #define	REP_PROTOCOL_NOTIFY_PGTYPE 2
782 
783 struct rep_protocol_wait_request {
784 	enum rep_protocol_requestid rpr_request;
785 	uint32_t rpr_entityid;
786 };
787 
788 struct rep_protocol_snapshot_take {
789 	enum rep_protocol_requestid rpr_request;	/* SNAPSHOT_TAKE */
790 	uint32_t rpr_entityid_src;
791 	uint32_t rpr_entityid_dest;
792 	int	rpr_flags;
793 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
794 };
795 #define	REP_SNAPSHOT_NEW	0x00000001
796 #define	REP_SNAPSHOT_ATTACH	0x00000002
797 
798 struct rep_protocol_snapshot_take_named {
799 	enum rep_protocol_requestid rpr_request; /* SNAPSHOT_TAKE_NAMED */
800 	uint32_t rpr_entityid_src;
801 	uint32_t rpr_entityid_dest;
802 	char	rpr_svcname[REP_PROTOCOL_NAME_LEN];
803 	char	rpr_instname[REP_PROTOCOL_NAME_LEN];
804 	char	rpr_name[REP_PROTOCOL_NAME_LEN];
805 };
806 
807 struct rep_protocol_snapshot_attach {
808 	enum rep_protocol_requestid rpr_request;	/* SNAPSHOT_ATTACH */
809 	uint32_t rpr_entityid_src;
810 	uint32_t rpr_entityid_dest;
811 };
812 
813 struct rep_protocol_backup_request {
814 	enum rep_protocol_requestid rpr_request;	/* BACKUP */
815 	uint32_t rpr_changeid;
816 	char rpr_name[REP_PROTOCOL_NAME_LEN];
817 };
818 
819 struct rep_protocol_annotation {
820 	enum rep_protocol_requestid rpr_request;	/* SET_ANNOTATION */
821 	char rpr_operation[REP_PROTOCOL_NAME_LEN];
822 	char rpr_file[MAXPATHLEN];
823 };
824 
825 /*
826  * Response structures
827  */
828 typedef struct rep_protocol_response {
829 	rep_protocol_responseid_t rpr_response;
830 } rep_protocol_response_t;
831 
832 struct rep_protocol_integer_response {
833 	rep_protocol_responseid_t rpr_response;
834 	uint32_t rpr_value;
835 };
836 
837 struct rep_protocol_name_response {	/* response to ENTITY_NAME */
838 	rep_protocol_responseid_t rpr_response;
839 	char rpr_name[REP_PROTOCOL_NAME_LEN];
840 };
841 
842 struct rep_protocol_fmri_response {
843 	rep_protocol_responseid_t rpr_response;
844 	char rpr_fmri[REP_PROTOCOL_FMRI_LEN];
845 };
846 
847 struct rep_protocol_value_response {
848 	rep_protocol_responseid_t rpr_response;
849 	rep_protocol_value_type_t rpr_type;
850 	char			rpr_value[2 * REP_PROTOCOL_VALUE_LEN + 1];
851 };
852 
853 #ifdef	__cplusplus
854 }
855 #endif
856 
857 #endif	/* _REPCACHE_PROTOCOL_H */
858