Documentation
¶
Overview ¶
Package transport implements the iSCSI TCP transport layer: connection management, PDU framing over TCP streams, concurrent read/write pumps, ITT-based response routing, and buffer pool management.
Index ¶
- Constants
- func GetBHS() *[pdu.BHSLength]byte
- func GetBuffer(size int) []byte
- func PutBHS(b *[pdu.BHSLength]byte)
- func PutBuffer(b []byte)
- func ReadPump(ctx context.Context, r io.Reader, router *Router, unsolicitedCh chan<- *RawPDU, ...) error
- func WithReadFaultAfter(n int64, err error) func(int64) error
- func WithWriteFaultAfter(n int64, err error) func(int64) error
- func WritePump(ctx context.Context, w io.Writer, writeCh <-chan *RawPDU, logger *slog.Logger, ...) error
- func WriteRawPDU(w io.Writer, p *RawPDU, digestByteOrder ...binary.ByteOrder) error
- type Conn
- func (c *Conn) Close() error
- func (c *Conn) DigestByteOrder() binary.ByteOrder
- func (c *Conn) DigestData() bool
- func (c *Conn) DigestHeader() bool
- func (c *Conn) MaxRecvDSL() uint32
- func (c *Conn) NetConn() net.Conn
- func (c *Conn) SetDeadline(t time.Time) error
- func (c *Conn) SetDigestByteOrder(bo binary.ByteOrder)
- func (c *Conn) SetDigests(header, data bool)
- func (c *Conn) SetMaxRecvDSL(maxDSL uint32)
- type FaultConn
- type RawPDU
- type Router
Constants ¶
const ( HookSend uint8 = 0 HookReceive uint8 = 1 )
PDU hook direction constants. These live in the transport package to avoid a circular dependency between transport and session.
const DefaultRouterBufDepth = 64
Router manages ITT-based PDU dispatch. When a command goroutine sends a request, it registers an ITT via Register and waits on the returned channel. When the read pump receives a response, it calls Dispatch with the ITT from the BHS to deliver the response to the correct waiter. DefaultRouterBufDepth is the default persistent channel buffer depth.
Variables ¶
This section is empty.
Functions ¶
func GetBHS ¶
GetBHS returns a reusable 48-byte BHS buffer from the pool. The caller must call PutBHS when done.
func GetBuffer ¶
GetBuffer returns a byte slice of at least size bytes from a size-class pool. The returned slice may be larger than requested. The caller must call PutBuffer when done. The returned slice is NOT zeroed.
func PutBuffer ¶
func PutBuffer(b []byte)
PutBuffer returns a buffer to the appropriate size-class pool. Buffers larger than the largest pool class are not returned.
func ReadPump ¶
func ReadPump(ctx context.Context, r io.Reader, router *Router, unsolicitedCh chan<- *RawPDU, digestHeader, digestData bool, logger *slog.Logger, pduHook func(uint8, *RawPDU), maxRecvDSL uint32, digestByteOrder binary.ByteOrder) error
ReadPump continuously reads PDUs from r and dispatches them by ITT. PDUs with the reserved ITT 0xFFFFFFFF (unsolicited target PDUs such as NOP-In pings and async messages) are sent to unsolicitedCh. All other PDUs are delivered via router.Dispatch. Returns when the read fails (connection closed) or ctx is cancelled.
func WithReadFaultAfter ¶
WithReadFaultAfter returns a fault function that triggers the given error once cumulative bytes read reaches or exceeds n.
func WithWriteFaultAfter ¶
WithWriteFaultAfter returns a fault function that triggers the given error once cumulative bytes written reaches or exceeds n.
func WritePump ¶
func WritePump(ctx context.Context, w io.Writer, writeCh <-chan *RawPDU, logger *slog.Logger, pduHook func(uint8, *RawPDU), digestByteOrder binary.ByteOrder) error
WritePump owns all writes to the underlying connection. It receives RawPDUs from writeCh and serializes them to w one at a time, preventing TCP byte interleaving (Pitfall 7). Returns when ctx is cancelled or writeCh is closed.
Types ¶
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn wraps a net.Conn with iSCSI transport-level state such as digest negotiation flags and MaxRecvDataSegmentLength enforcement.
func Dial ¶
Dial connects to an iSCSI target at the given TCP address using the provided context for timeout/cancellation control.
func NewConnFromNetConn ¶
NewConnFromNetConn wraps an existing net.Conn as a transport Conn. Used by the session layer and tests when the TCP connection is already established (e.g., after login).
func (*Conn) DigestByteOrder ¶
DigestByteOrder returns the configured digest byte order. Returns LittleEndian if not explicitly set.
func (*Conn) DigestData ¶
DigestData reports whether data digests are enabled.
func (*Conn) DigestHeader ¶
DigestHeader reports whether header digests are enabled.
func (*Conn) MaxRecvDSL ¶
MaxRecvDSL returns the negotiated MaxRecvDataSegmentLength. Zero means not yet negotiated (no limit enforced).
func (*Conn) NetConn ¶
NetConn returns the underlying net.Conn. Used for testing and low-level access.
func (*Conn) SetDeadline ¶
SetDeadline sets the read and write deadlines on the underlying connection.
func (*Conn) SetDigestByteOrder ¶
SetDigestByteOrder configures the byte order used for reading and writing CRC32C digest values on the wire. Defaults to LittleEndian, which matches the Linux kernel iSCSI target (LIO) and open-iscsi initiator.
Some targets (notably certain enterprise SAN firmware) use BigEndian. RFC 7143 Section 12.1 does not specify byte order for digest values; this is an interoperability parameter.
func (*Conn) SetDigests ¶
SetDigests configures whether header and data digests are active on this connection. Called after login negotiation completes.
func (*Conn) SetMaxRecvDSL ¶
SetMaxRecvDSL sets the MaxRecvDataSegmentLength for this connection. The transport layer enforces this limit when framing incoming PDUs.
type FaultConn ¶
FaultConn wraps a net.Conn with injectable read/write faults for deterministic error injection in tests. Faults trigger based on cumulative byte counts, allowing precise control over when errors occur during iSCSI PDU exchanges.
func NewFaultConn ¶
NewFaultConn wraps conn with optional read and write fault functions. If readFault or writeFault is nil, the corresponding operation passes through to the underlying connection without fault injection.
func (*FaultConn) Read ¶
Read implements io.Reader with fault injection. Before each read, it checks the readFault function (if set) against the cumulative byte count.
func (*FaultConn) SetReadFault ¶
SetReadFault sets or replaces the read fault function at runtime.
func (*FaultConn) SetWriteFault ¶
SetWriteFault sets or replaces the write fault function at runtime.
type RawPDU ¶
type RawPDU struct {
BHS [pdu.BHSLength]byte
AHS []byte // nil if no AHS
DataSegment []byte // copied out, caller-owned
HeaderDigest uint32 // 0 if not present
DataDigest uint32 // 0 if not present
HasHDigest bool
HasDDigest bool
}
RawPDU holds the raw bytes of an iSCSI PDU as read from or to be written to the wire. The DataSegment is copied into caller-owned memory (not pooled).
func ReadRawPDU ¶
func ReadRawPDU(r io.Reader, digestHeader, digestData bool, maxRecvDSL uint32, digestByteOrder ...binary.ByteOrder) (*RawPDU, error)
ReadRawPDU reads a complete iSCSI PDU from r. It uses io.ReadFull exclusively to handle partial TCP reads correctly (Pitfall 6). The digest booleans control whether header and data digests are expected on the wire.
The returned RawPDU's DataSegment is a freshly allocated slice (caller-owned). Pool scratch buffers are used internally and returned after copying.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
func NewRouter ¶
NewRouter creates a Router with an empty pending map. persistentDepth sets the buffer depth for persistent registrations (0 = DefaultRouterBufDepth).
func (*Router) AllocateITT ¶
AllocateITT allocates the next available ITT without registering a channel. The caller registers separately via RegisterPersistent.
func (*Router) Dispatch ¶
Dispatch delivers pdu to the channel registered for the given ITT. For non-persistent entries, it removes the entry after delivery. Returns true if the ITT was found, false otherwise.
func (*Router) PendingCount ¶
PendingCount returns the number of ITTs currently awaiting responses. Intended for diagnostics and testing.
func (*Router) Register ¶
Register allocates the next available ITT (skipping the reserved value 0xFFFFFFFF) and returns it along with a receive-only channel that will carry the response PDU. The channel has capacity 1 so the dispatcher never blocks. The entry is removed after the first Dispatch.
func (*Router) RegisterPersistent ¶
RegisterPersistent creates a persistent registration for the given ITT. Unlike Register, the entry is NOT removed after Dispatch -- it survives multiple PDU deliveries. The session layer uses this for SCSI commands that receive multiple Data-In PDUs before completion. The caller must call Unregister when the command completes.
func (*Router) Unregister ¶
Unregister removes a pending ITT entry without delivering a PDU. Used for timeout/cancellation cleanup.