diff --git a/doc/users-guide/users-guide-packet.adoc b/doc/users-guide/users-guide-packet.adoc
index e3be23c..82836d0 100644
--- a/doc/users-guide/users-guide-packet.adoc
+++ b/doc/users-guide/users-guide-packet.adoc
@@ -282,3 +282,121 @@ larger than the underlying segment size. The call may also fail if the
 requested alignment is too high. Alignment limits will vary among different ODP
 implementations, however ODP requires that all implementations support
 requested alignments of at least 32 bytes.
+
+==== Packet Splices and References
+To support efficient multicast, retransmit, and related processing, ODP
+supports two additional types of packet manipulation: _splices_ and
+_references_.
+
+===== Splices
+A _splice_ is formed by connecting a _header packet_ to a _base packet_ at a
+specified byte offset into the base packet using the API:
+
+[source,c]
+-----
+spliced_pkt = odp_packet_splice(hdr_pkt, base_pkt, offset);
+-----
+
+If the splice fails, `ODP_PACKET_INVALID` is returned and both `hdr_pkt` and
+`base_pkt` are unchanged. Otherwise the `hdr_pkt` is replaced by the returned
+`spliced_pkt`, which should be used to refer to the splice. The basic splice
+operation is show below:
+
+.Packet Splicing
+image::splice.svg[align="center"]
+
+Note that the original `base_pkt` is still valid and viewable independent of
+the splice. However, when viewed through the returned splice packet handle the
+bytes contained in `base_pkt` prior to the splice offset are invisible.
+
+A splice thus creates a "view" on a base packet that consists of a unique
+_prefix_ followed by a shared _payload_. This is important because multiple
+headers can be spliced onto a single base packet:
+
+[source,c]
+-----
+splice1 = odp_packet_splice(hdr_pkt1, base_pkt, offset1);
+splice2 = odp_packet_splice(hdr_pkt2, base_pkt, offset2);
+-----
+The result of these two calls is shown here:
+
+.Payload Sharing via Splicing
+image::doublesplice.svg[align="center"]
+
+Here two separate header packets are spliced onto the same base packet, each
+at their own specified offset, which may or may not be the same. The result is
+three packets visible to the application:
+
+* The original `base_pkt`, which can still be accessed directly.
+* The first splice, which consists of `hdr_pkt1` followed by bytes contained in
+`base_pkt` starting at `offset1`.
+* The second splice, which consists of `hdr_pkt2` followed by bytes contained
+in `base_pkt` starting at `offset2`.
+
+Only a single copy of the bytes in `base_pkt` that are common to the two
+splices exist. Splices therefore permit multiple headers to be attached to a
+shared payload in an efficient manner.
+
+Once spliced, the `base_pkt` may be freed via a call to `odp_packet_free()`,
+however the bytes that are part of `base_pkt` that are visible through any
+splices are retained until the splice packets are themselves freed. Splices
+can thus be used to retain a copy of a packet after it (or another splice
+based on it) has been transmitted or otherwise consumed.
+
+===== References
+A _packet reference_ is a special type of splice with a null header. For
+convenience, a separate API is provided for creating packet references:
+
+[source,c]
+-----
+ref_pkt = odp_packet_ref(base_pkt, offset);
+-----
+Again, if the reference fails `ODP_PACKET_INVALID` is returned and no other
+effect is seen. A successful call results in the following behavior:
+
+.Packet Reference
+image::pktref.svg[align="center"]
+
+Similar to a splice, a reference permits the creation of multiple views on
+a base packet that can be processed or freed independently. The only
+difference is that a reference does not have an application-supplied header
+prefixed to it.
+
+===== Data Sharing with Splices and References
+Because a `base_pkt` is a shared object in both splices and references,
+applications must observe certain disciplines when working with them.
+In partiular, any change to a `base_pkt` following the creation of a splice
+or reference will be visible through any splice/reference handles to them,
+and this can lead to unpredictable behavior. For best portability and
+consistency, it is recommended that a `base_pkt` be treated as read only once
+it has been successfully spliced.
+
+To assist applications in working with splices, ODP provides two additional
+APIs:
+
+[source,c]
+-----
+int odp_packet_is_a_splice(odp_packet_t pkt);
+
+int odp_packet_is_spliced(odp_packet_t pkt);
+-----
+The `odp_packet_is_a_splice()` API says whether a packet was created via a call
+to `odp_packet_splice()` or `odp_packet_ref()`. The `odp_packet_is_spliced()`
+API says whether a packet has had a splice created on it, _i.e.,_ if it is a
+`base_pkt` for some other splice.
+
+Note that architecturally, ODP does not limit splicing and so it is possible that
+a splice may be used as a `base_pkt` for creating another splice. Such
+_compound splices_ may or may not be supported by individual ODP implementations
+so for best portability it is recommended that applications restrict themselves
+to using simple splices.
+
+Note also that a packet may not be spliced to itself, nor may circular splice
+relationships be formed, _e.g.,_ packet A is spliced onto packet B and B is
+spliced onto A. Results are undefined if such circular relationships are attempted.
+
+The intent of splices and references is to permit easy and efficient manipulation
+of packets that consist of unique headers and shared payloads. This means that
+normal headroom manipulation (`odp_packet_push_head()`, etc.) affects only the
+data unique to an individual splice or reference, allowing customized headers to
+be attached to shared payloads.
