mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-20 18:20:49 +01:00
1467 lines
46 KiB
Plaintext
1467 lines
46 KiB
Plaintext
.NC "The Design of the ARGO Transport Entity"
|
|
.sh 1 "Protocol Hooks"
|
|
.pp
|
|
The design of the AOS kernel IPC support to some
|
|
extent mandates the
|
|
design of protocols.
|
|
Each protocol must provide the following
|
|
protocol hooks, which are procedures called through a
|
|
protocol switch table
|
|
(an array of type \fIprotosw\fR as described in
|
|
Chapter Five.
|
|
.ip "pr_input()" 5
|
|
Called when data are to be passed up from a lower layer.
|
|
.ip "pr_output()" 5
|
|
Called when data are to be passed down from a higher layer.
|
|
.ip "pr_init()" 5
|
|
Called when the system is brought up.
|
|
.ip "pr_fasttimo()" 5
|
|
Called every 200 milliseconds by the clock functional unit.
|
|
.ip "pr_slowtimo()" 5
|
|
Called every 500 milliseconds by the clock functional unit.
|
|
.ip "pr_drain()" 5
|
|
This is meant to be called when buffer space is low.
|
|
Each protocol is expected to provide this routine to free
|
|
non-critical buffer space.
|
|
This is not yet called anywhere.
|
|
.ip "pr_ctlinput()" 5
|
|
Used for exchanging information between
|
|
protocols, such as notifying a transport protocol of changes
|
|
in routing or configuration information.
|
|
.ip "pr_ctloutput()" 5
|
|
Supports the protocol-dependent
|
|
\fIgetsockopt()\fR
|
|
and
|
|
\fIsetsockopt()\fR
|
|
options.
|
|
.ip "pr_usrreq()" 5
|
|
Called by the socket code to pass along a \*(lquser request\*(rq -
|
|
in other words a service primitive.
|
|
This call is also used for other protocol functions.
|
|
The functions served by the \fIpr_usrreq()\fR routine are:
|
|
.ip " PRU_ATTACH" 10
|
|
Creates a protocol control block and attaches it to a given socket.
|
|
Called as a result of a \fIsocket()\fR system call.
|
|
.ip " PRU_DISCONNECT" 10
|
|
Called as a result of a
|
|
\fIclose()\fR system call.
|
|
Initiates disconnection.
|
|
.ip " PRU_DETACH" 10
|
|
Disassociates a protocol control block from a socket and recycles
|
|
the buffer space used for the protocol control block.
|
|
Called after PRU_DISCONNECT.
|
|
.ip " PRU_SHUTDOWN" 10
|
|
Called as a result of a
|
|
\fIshutdown()\fR system call.
|
|
If the protocol supports the notion of half-open connections,
|
|
this closes the connection in one direction or both directions,
|
|
depending on the arguments passed to
|
|
\fIshutdown\fR.
|
|
.ip " PRU_BIND" 10
|
|
Gives an address to a socket.
|
|
Called as a result of a
|
|
\fIbind()\fR system call, also
|
|
when
|
|
socket without a bound address is used.
|
|
In the latter case, an unused transport suffix is located and
|
|
bound to the socket.
|
|
.ip " PRU_LISTEN" 10
|
|
Called as a result of a
|
|
\fIlisten()\fR system call.
|
|
Marks the socket as willing to queue incoming connection
|
|
requests.
|
|
.ip " PRU_CONNECT" 10
|
|
Called as a result of a
|
|
\fIconnect()\fR system call.
|
|
Initiates a connection request.
|
|
.ip " PRU_ACCEPT" 10
|
|
Called as a result of an
|
|
\fIaccept()\fR system call.
|
|
Dequeues a pending connection request, or blocks waiting for
|
|
a connection request to arrive.
|
|
In the latter case, it marks the socket as willing to accept
|
|
connections.
|
|
.ip " PRU_RCVD" 10
|
|
The protocol module is expected to have put incoming data
|
|
into the socket's receive buffer, \fIso_rcv\fR.
|
|
When a receive primitive is used
|
|
(\fIrecv(), recvmsg(), recvfrom(),
|
|
read(), readv(), \fRand
|
|
\fIrecvv()\fR system calls)
|
|
the socket code module copies data from the
|
|
\fIso_rcv\fR to the user's
|
|
address space.
|
|
The protocol module may arrange to be informed each time the socket code
|
|
does this, in which case the socket code calls \fIpr_usrreq\fR(PRU_RCVD)
|
|
after the data were copied to the user.
|
|
.ip " PRU_SEND" 10
|
|
This performs the protocol-dependent part of a send primitive
|
|
(\fIsend(), sendmsg(), sendto(), write(), writev(),
|
|
\fRand \fIsendv()\fR system calls).
|
|
The socket code
|
|
(procedures \fIsendit() and \fIsosend()\fR)
|
|
moves outgoing data from the user's
|
|
address space into a chain of \fImbufs\fR.
|
|
The socket code takes as much data from the user as it
|
|
determines will fit into the outgoing socket buffer, so_snd.
|
|
It passes this much data in the form of an mbuf chain to the protocol
|
|
via \fIpr_usrreq\fR(PRU_SEND).
|
|
If there are more data than
|
|
the so_snd can accommodate,
|
|
the socket code, which is running on behalf of a user process,
|
|
puts the user process to sleep.
|
|
The protocol module is expected to wake up the user process when
|
|
more room appears in so_snd.
|
|
.ip " PRU_ABORT" 10
|
|
Called when a socket is closed and that socket
|
|
is accepting connections and has
|
|
queued pending
|
|
connection requests or
|
|
partially open connections.
|
|
.ip " PRU_CONTROL" 10
|
|
Called as a result of an
|
|
\fIioctl()\fR system call.
|
|
.ip " PRU_SENSE" 10
|
|
Called as a result of an
|
|
\fIfstat()\fR system call.
|
|
.ip " PRU_RCVOOB" 10
|
|
Performs the work of receiving \*(lqout-of-band\*(rq data.
|
|
The socket module has already allocated an mbuf into which
|
|
the protocol module is expected to put the incoming
|
|
\*(lqout-of-band\*(rq data.
|
|
The socket code will then move the data from this mbuf
|
|
to the user's address space.
|
|
.ip " PRU_SENDOOB" 10
|
|
Performs the work of sending \*(lqout-of-band\*(rq data.
|
|
The socket module has already moved the data
|
|
from the user's address space into a chain of mbufs,
|
|
which it now passes to the protocol module.
|
|
.ip " PRU_SOCKADDR" 10
|
|
Supports the system call
|
|
\fIgetsockname()\fR.
|
|
Puts the socket's bound address into an mbuf.
|
|
.ip " PRU_PEERADDR" 10
|
|
Supports the system call
|
|
\fIgetpeername\fR().
|
|
Puts the peer's address into an mbuf.
|
|
.ip " PRU_CONNECT2" 10
|
|
This is used in the Unix domain to support pipes.
|
|
It is not generally supported by transport protocols.
|
|
.ip " PRU_FASTTIMO, PRU_SLOWTIMO" 10
|
|
These are superfluous.
|
|
None of the transport protocols uses them.
|
|
.ip " PRU_PROTORCV, PRU_PROTOSEND" 10
|
|
None of the transport protocols uses these.
|
|
.ip " PRU_SENDEOT" 10
|
|
This was added to support TP.
|
|
This indicates that the end of the data sent in this
|
|
send primitive should
|
|
be marked by the protocol as the end of the TSDU.
|
|
.sh 1 "The Interface Between the Transport Entity and Lower Layers"
|
|
.pp
|
|
The transport layer may run over a network layer such as IP
|
|
or the ISO connectionless network layer,
|
|
or it may run over a multi-purpose layer such as the service
|
|
provided by X.25.
|
|
X.25 is viewed as a network layer when
|
|
TP runs over X.25, and as a
|
|
subnetwork layer
|
|
when IP is running over X.25.
|
|
The software interface between data link and network layers differs
|
|
considerably from the software interface between transport and network
|
|
layers in AOS.
|
|
For this reason some modification of the transport-to-lower-layer
|
|
interface is necessary to support the suite of protocols included in
|
|
ARGO.
|
|
.pp
|
|
In AOS it is assumed that the transport layer will run over one
|
|
and only one network layer, and therefore it may call the
|
|
network layer output procedure directly.
|
|
In order to allow TP to run over a set of lower layers,
|
|
all domain-specific functions have been put into a set of routines
|
|
that are called indirectly through a domain-specific switch table.
|
|
The primary reason for this is that the transport and network
|
|
layers share information, mostly information pertaining to addresses.
|
|
The protocol control blocks for different network layers
|
|
differ, so the transport layer cannot just directly
|
|
access the network layer's pcb.
|
|
Similarly, a network layer may not directly access the transport
|
|
pcb because a multitude of transport protocols can run over each
|
|
of the network protocols.
|
|
.pp
|
|
To permit different network-layer protocol control blocks to coexist
|
|
under one transport layer, all transport-dependent control
|
|
information was put into a transport-specific protocol control block.
|
|
A new field, \fIso_tpcb\fR,
|
|
was added to the \fIsocket\fR structure to hold a pointer to
|
|
the transport-layer protocol control block.
|
|
The existing
|
|
field \fCso_pcb\fR is used for the network layer pcb.
|
|
.pp
|
|
The following structure was added to allow domain-specific
|
|
functions to be called indirectly.
|
|
All these functions operate on a network-layer pcb.
|
|
.pp
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l s s s.
|
|
struct nl_protosw {
|
|
.T&
|
|
l l l l.
|
|
+int+nlp_afamily;+/* address family */
|
|
+int+(*nlp_putnetaddr)();+/* puts addrs in pcb */
|
|
+int+(*nlp_getnetaddr)();+/* gets addrs from pcb */
|
|
+int+(*nlp_putsufx)();+/* transp suffix -> pcb */
|
|
+int+(*nlp_getsufx)();+/* gets t-suffix */
|
|
+int+(*nlp_recycle_suffix)();+/* zeroes suffix */
|
|
+int+(*nlp_mtu)();+/* get maximum
|
|
+++transmission unit size */
|
|
+int+(*nlp_pcbbind)();+/* bind to pcb */
|
|
+int+(*nlp_pcbconn)();+/* connect */
|
|
+int+(*nlp_pcbdisc)();+/* disconnect */
|
|
+int+(*nlp_pcbdetach)();+/* detach pcb */
|
|
+int+(*nlp_pcballoc)();+/* allocate a pcb */
|
|
+int+(*nlp_output)();+/* emit packet */
|
|
+int+(*nlp_dgoutput)();+/* emit datagram */
|
|
+caddr_t+nlp_pcblist;+/* list of pcbs
|
|
+++for management
|
|
+++of connections */
|
|
};
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
The switch is based on the address family chosen when the
|
|
\fIsocket()\fR system call is made prior to connection establishment.
|
|
This unfortunately ties the address family to the domain,
|
|
but the only alternative is to add an argument to the \fIsocket()\fR
|
|
system call to let the user specify the desired network layer.
|
|
In the case of a connection oriented environment with no multi-homing,
|
|
it would be possible to determine which network layer is to be
|
|
used
|
|
from routing
|
|
information, but to do this requires unrealistic assumptions
|
|
about the environment.
|
|
For these reasons, linking the address family to the network
|
|
layer protocol is seen as the least of the evils.
|
|
The transport suffixes are kept in the network layer's pcb
|
|
as well as in the transport layer because
|
|
full transport address pairs are used to identify a connection
|
|
in the Internet domain.
|
|
.sh 1 "The Architecture of the Transport Protocol Entity"
|
|
.pp
|
|
A set of protocol hooks is required
|
|
by the AOS IPC architecture.
|
|
These hooks are used by the protocol-independent parts of the kernel
|
|
to gain entry to protocol-specific code.
|
|
The protocol code can be entered in one of the following ways:
|
|
.ip "1) " 5
|
|
at boot time, when autoconfiguration
|
|
initializes each protocol through
|
|
the
|
|
\fIpr_init()\fR
|
|
hook,
|
|
.ip "2) " 5
|
|
from above, either
|
|
a user program making a system call, through
|
|
the \fIpr_usrreq()\fR or \fIpr_ctloutput()\fR hooks, or
|
|
from a higher layer protocol using the
|
|
\fIpr_output()\fR hook,
|
|
.ip "3) " 5
|
|
from below, a device interrupt servicing an incoming packet
|
|
through the \fIpr_input()\fR and \fIpr_ctlinput()\fR hooks, and
|
|
.ip "4) " 5
|
|
from a clock interrupt through the \fIpr_slowtimo()\fR
|
|
or the
|
|
\fIpr_fasttimo()\fR hook.
|
|
.\" FIGURE
|
|
.so figs/trans_flow.nr
|
|
.\".so figs/trans_flow.grn
|
|
.pp
|
|
The protocol code can be divided into
|
|
the following modules, which are described in more detail below.
|
|
.CF
|
|
shows the flow of data and control
|
|
among these modules.
|
|
.in +5
|
|
.ip "Timers and References:" 5
|
|
The code executed on behalf of \fIpr_slowtimo()\fR.
|
|
The fast timeout is not used by TP.
|
|
.ip "Driver:" 5
|
|
This is the finite state machine for TP.
|
|
.ip "Input: " 5
|
|
This is the module that decodes incoming packets,
|
|
identifies or creates the pcb for which
|
|
the packet is destined, and creates an "event" to
|
|
pass to the driver.
|
|
.ip "Output:" 5
|
|
This is the module that creates a packet header of a given type
|
|
with fields containing
|
|
values that are appropriate to the connection
|
|
on which the packet is being sent, appends data if necessary,
|
|
and hands a packet
|
|
to the lower layer, according to the transport-to-lower-layer
|
|
interface.
|
|
.ip "Send: " 5
|
|
This module packetizes data from the outbound
|
|
socket buffer, \fIso_snd\fR,
|
|
handles retransmissions of packetized data, and
|
|
drops packetized data from the retransmission queue.
|
|
.ip "Receive:" 5
|
|
This module reorders packets if necessary,
|
|
depacketizes data, passes it to the socket code module,
|
|
and determines when acknowledgments should be sent.
|
|
.in -5
|
|
.sh 1 "Timers and References"
|
|
.pp
|
|
TP identifies sockets by \fIreference numbers\fR, or
|
|
\fIreferences\fR,
|
|
which are \*(lqfrozen\*(rq (may not be reassigned)
|
|
until some locally defined time after
|
|
a connection is broken and its protocol control block
|
|
is discarded.
|
|
An array of \fIreference blocks\fR is maintained by TP.
|
|
The reference number of a reference block is its
|
|
offset in the array.
|
|
When a reference block is in use it contains
|
|
a pointer to the pcb for the socket to which the
|
|
reference applies.
|
|
.pp
|
|
The system clock calls the \fIpr_slowtimo()\fR and
|
|
\fIpr_fasttimo()\fR hooks for each protocol in the protocol switch table
|
|
every 500 and 200 microseconds, respectively.
|
|
Each protocol handles its own timers its own way.
|
|
The timers in TP take two forms
|
|
- those that typically are cancelled and
|
|
those that usually expire.
|
|
The latter form may have more than one instantiation at any given
|
|
time.
|
|
The former may not.
|
|
The two are implemented slightly
|
|
differently for the sake of performance.
|
|
.pp
|
|
The timers that normally expire
|
|
are kept in a queue, their values all relative
|
|
to the value of preceding timer.
|
|
Thus all timer values are decremented by a single
|
|
operation on the value of the first timer.
|
|
The timer is represented by the Ecallout structure:
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l s s s.
|
|
struct Ecallout {
|
|
.T&
|
|
l l l l.
|
|
+int+c_time;+/* incremental time */
|
|
+int+c_func;+/* function to call */
|
|
+u_int+c_arg1;+/* argument to routine */
|
|
+u_int+c_arg2;+/* argument to routine */
|
|
+int+c_arg3;+/* argument to routine */
|
|
+struct Ecallout+*c_next;
|
|
};
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
When an Ecallout structure migrates to the head
|
|
of the E timer list, and its \fIc_time\fR
|
|
field is decremented to zero,
|
|
the function stored in \fIc_func\fR is
|
|
called, with \fIc_arg1, c_arg2\fR, and \fIc_arg3\fR
|
|
as arguments.
|
|
Setting and cancelling these timers
|
|
are accomplished by a linear search and one
|
|
insertion or deletion from the timer queue.
|
|
This queue is linked to the
|
|
reference block associated with a communication endpoint.
|
|
This form used for the reference timer
|
|
and for the retransmission timers for data TPDUs.
|
|
.pp
|
|
The second form of timer, the type that
|
|
typically is cancelled, is used for several
|
|
timers - the inactivity timer, the sendack timer,
|
|
and the retransmission
|
|
timer for all types of TPDUs except data TPDUs.
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l s s s.
|
|
struct Ccallout {
|
|
.T&
|
|
l l l l.
|
|
+int+c_time;+/* incremental time */
|
|
+int+c_active;+/* this timer is active? */
|
|
};
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
All of these timers are stored
|
|
directly
|
|
in the reference block.
|
|
These timers are decremented in one linear scan of
|
|
the reference blocks.
|
|
Cancelling, setting, and both
|
|
cancelling and resetting one of these timers is accomplished by a
|
|
single assignment to an array element.
|
|
.sh 1 "Driver"
|
|
.pp
|
|
This is the finite state machine for TP.
|
|
A connection is managed by the finite state machine (fsm).
|
|
All events that pertain to a connection cause the
|
|
finite state machine driver to be called.
|
|
The driver takes two arguments - the pcb for the connection
|
|
and an event structure.
|
|
The event structure contains a field that discriminates
|
|
the different types of events, and a union of
|
|
structures that are specific to the event types.
|
|
The driver evaluates a set of predicates based on the current
|
|
state of the finite state machine (which is kept in the pcb) and the event type.
|
|
The result of the predicate evaluation determines
|
|
a set of actions to take and a state transition.
|
|
The driver takes the actions and if they complete
|
|
without errors, the driver makes the state transition.
|
|
.pp
|
|
The states, event types, predicates, actions, and state transitions are all
|
|
specified as a \fIxebec transition file\fR.
|
|
\fIXebec\fR is a utility that takes a human-readable description
|
|
of a finite state machine
|
|
and produces a set of tables and C source code for the driver.
|
|
The driver procedure is called \fItp_driver()\fR.
|
|
It is located in a file generated by xebec,
|
|
\fCtp_driver.c\fR.
|
|
For more details about xebec, see the manual page \fIxebec(1)\fR.
|
|
.pp
|
|
The transition file for TP is \fCtp.trans\fR,
|
|
and it is a good place to begin a perusal of the TP
|
|
source code.
|
|
.sh 1 "Input"
|
|
.pp
|
|
This is the module that decodes an incoming packet,
|
|
locates or creates the pcb for which
|
|
the packet is destined, and creates an event to
|
|
pass to the driver.
|
|
The network layer passes a packet up to the appropriate
|
|
transport layer by indirectly calling a transport input
|
|
routine through the protocol switch table for the network
|
|
domain.
|
|
There is one protocol switch entry for TP for each domain in which
|
|
TP will run (Internet, ISO).
|
|
In the Internet domain, the protocol switch field \fIpr_input()\fR
|
|
takes the value \fItpip_input()\fR.
|
|
This procedure accepts a packet from IP, with the IP header
|
|
still intact.
|
|
It extracts the network addresses from the IP header,
|
|
strips the IP header, and calls the domain-independent
|
|
input procedure for TP,
|
|
\fItp_input()\fR.
|
|
\fITp_input()\fR
|
|
decodes a TPDU.
|
|
The multitude of options, the variable-length
|
|
nature of the options, the semantics of the
|
|
options, and the possible combinations of concatenated
|
|
TPDUs make this a
|
|
complex procedure.
|
|
It is sensitive to changes, and from
|
|
the point of view of a software maintenance, it is a
|
|
potential hazard.
|
|
Because it is in the
|
|
critical path of TP however, some compromise
|
|
was made between maintainability and efficiency.
|
|
Multiple copies of sections of code were avoided as much as
|
|
possible,
|
|
not for the sake of saving space, but rather for the sake
|
|
of maintainability.
|
|
Ironically,
|
|
this detracts somewhat from the readability of the code.
|
|
.pp
|
|
Once a TPDU has been decoded and a pcb has been
|
|
identified for the TPDU,
|
|
the appropriate fields of the TPDU
|
|
are extracted and their values are placed in
|
|
an event structure.
|
|
Finally, \fItp_driver()\fR is called with
|
|
the event structure and the pcb as parameters.
|
|
.sh 1 "Output"
|
|
.pp
|
|
This module creates a TPDU header of a given type
|
|
with field values that are appropriate to the connection
|
|
on which the TPDU is being sent, appends data if necessary,
|
|
and hands a TPDU
|
|
to the lower layer according to the transport-to-lower-layer
|
|
interface.
|
|
Whenever a TPDU is to be sent to the peer or prospective peer,
|
|
the function \fItp_emit()\fR
|
|
is called, passing as arguments the pcb a TPDU type and several miscellaneous
|
|
other type-specific arguments, possibly including some data.
|
|
The data are in the form of an mbuf chain.
|
|
\fITp_emit()\fR prepends to the data an mbuf containing a TP header,
|
|
fills in the fields of the header according to the parameters
|
|
given, performs the checksum if appropriate, and
|
|
calls a domain-specific output routine.
|
|
For the Internet domain, this output routine is
|
|
\fItpip_output()\fR, which takes
|
|
as arguments the mbuf chain representing the TPDU,
|
|
and a network level pcb.
|
|
Some protocol errors cannot be associated with
|
|
a connection
|
|
but require that TP issue
|
|
an ER TPDU or a DR TPDU.
|
|
When these errors occur the routine
|
|
\fItp_error_emit()\fR is called.
|
|
This procedure creates the appropriate type of TPDU
|
|
and passes it to a domain-dependent routine for transmitting datagrams.
|
|
In the Internet domain,
|
|
\fItpip_output_dg()\fR is called.
|
|
This takes as arguments an mbuf chain representing the TPDU,
|
|
a source network address, and a destination network address.
|
|
.sh 1 "Send"
|
|
.\" FIGURE
|
|
.so figs/mbufsnd.nr
|
|
.\".so figs/mbufsnd.grn
|
|
.pp
|
|
This module packetizes data from the outbound
|
|
socket buffer, \fIso_snd\fR,
|
|
handles retransmissions of packetized data, and
|
|
drops packetized data from the retransmission queue.
|
|
The major routine in this module is \fItp_send()\fR, which
|
|
takes a range of sequence numbers as arguments.
|
|
For each sequence number in the range,
|
|
it packetizes the an appropriate amount
|
|
of outbound data, and places the resulting TPDU on
|
|
a retransmission control queue subject to the
|
|
constraints imposed by the rules of expedited data,
|
|
maximum packet sizes, and end-of-TSDU markers.
|
|
.pp
|
|
The most complicating factor is that of managing
|
|
expedited data.
|
|
A normal datum may not be sent (for its first time) before the
|
|
acknowledgment of any expedited datum
|
|
that was received from the user after the
|
|
normal datum was received.
|
|
In order to enforce this rule,
|
|
each TPDU must be marked in some way
|
|
so that it will be known which expedited datum
|
|
must be delivered and acknowledged by the peer before this TPDU may be transmitted
|
|
for the first time.
|
|
Markers are placed in \fIso_snd\fR
|
|
when an
|
|
outgoing expedited datum arrives from the user.
|
|
A marker is an mbuf structure with an \fIm_len\fR
|
|
of zero, but with the data area nevertheless containing
|
|
the sequence number of an expedited data TPDU.
|
|
The \fIm_type\fR of a marker is a new type, MT_XPD.
|
|
.pp
|
|
\fITp_send()\fR stops packetizing data when it encounters a marker
|
|
for an unacknowledged expedited datum.
|
|
If it encounters a marker for an expedited TPDU that has already
|
|
been acknowledged, the marker is jettisoned.
|
|
.CF
|
|
illustrates the structure of the sending socket buffer used
|
|
for normal data.
|
|
.pp
|
|
When \fItp_send()\fR moves data from mbufs on \fIso_snd\fR to the retransmission
|
|
control queue, it needs to know
|
|
how many octets of data can be placed in each TPDU.
|
|
The appropriate amount depends on, among other things,
|
|
the maximum transmission unit of the network layer
|
|
on the route the packet will take.
|
|
To determine the maximum transmission unit,
|
|
TP queries the network layer through
|
|
the domain-dependent switch table's field, \fInl_mtu\fR.
|
|
In the Internet domain, this resolves to \fItp_inmtu()\fR.
|
|
The header sizes for the network and transport layers
|
|
also affect the amount of data that can go into a packet,
|
|
and these sizes depend on the connection's characteristics.
|
|
.pp
|
|
Once the maximum amount of data per TPDU is determined,
|
|
\fItp_send()\fR can pull this amount off the \fIso_snd\fR queue to form
|
|
a TPDU,
|
|
assign a TPDU sequence number,
|
|
and place the new TPDU on the
|
|
retransmission control queue.
|
|
The retransmission control queue is a list of mbuf chains.
|
|
Each mbuf chain represents one TPDU, preceded by an
|
|
\fIrtc structure\fR:
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l s s s.
|
|
struct tp_rtc {
|
|
.T&
|
|
l l l l.
|
|
+struct tp_rtc+*tprt_next;+/* next rtc struct in list */
|
|
+SeqNum+tprt_seq;+/* seq # of this TPDU */
|
|
+int+tprt_eot;+/* end of TSDU? */
|
|
+int+tprt_octets;+/* # octets in this TPDU */
|
|
+struct mbuf+*tprt_data;+/* ptr to the octets of data */
|
|
.\"/* Performance measurment info: */
|
|
.\"int tprt_window; /* in which call to tp_send() was
|
|
.\" * this TPDU formed?
|
|
.\" */
|
|
.\"struct timeval tprt_sess_time; /* time session received the
|
|
.\" * majority of the data for this packet on send;
|
|
.\" * on recv, this is the time it's given to session
|
|
.\" */
|
|
.\"struct timeval tprt_net_time; /* time first copy was given to net layer
|
|
.\" * on send; on receive it's the time received from
|
|
.\" * the network
|
|
.\" */
|
|
};
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
Once TPDUs are on the retransmission control queue,
|
|
they are retransmitted or dropped by the actions
|
|
of timers.
|
|
The procedure \fItp_sbdrop()\fR
|
|
removes the TPDUs from the retransmission queue.
|
|
It takes a sequence number as an argument and drops
|
|
all TPDUs up to and including the TPDU with that sequence number.
|
|
.pp
|
|
When an AK TPDU arrives, the values from
|
|
its credit and sequence number fields
|
|
are passed to \fItp_goodack()\fR, which
|
|
determines whether or not the AK brought any news with it,
|
|
and therefore whether TP can send more data
|
|
or expedited data.
|
|
If this AK acknowledges something heretofore unacknowledged,
|
|
\fItp_goodack()\fR drops the appropriate TPDU(s) from the retransmission
|
|
control list, computes the smoothed average round trip time
|
|
and standard deviation of the round trip time,
|
|
and updates
|
|
the retransmission timer based on these statistics.
|
|
It sets a flag in the pcb if the TP entity is obliged to
|
|
send the flow control confirmation parameter on its next
|
|
AK TPDU.
|
|
\fITp_goodack()\fR returns true if the AK brought some news with it,
|
|
either with respect to a change in credit or with respect to
|
|
new acknowledgments.
|
|
.pp
|
|
The function \fItp_goodXack()\fR is called when an XAK TPDU
|
|
arrives.
|
|
It takes the XAK sequence number as an argument and
|
|
determines if the XAK acknowledges the last XPD TPDU sent.
|
|
If so, it drops the expedited data from the outgoing
|
|
expedited data buffer.
|
|
By its definition in the TP specification,
|
|
the expedited data stream has a window
|
|
of size 1,
|
|
that is,
|
|
only one expedited datum (packet) can be buffered
|
|
at a time.
|
|
\fITp_goodXack()\fR returns true if the XAK acknowledged
|
|
the last XPD TPDU sent and the data were dropped,
|
|
and it returns false if the acknowledgment caused no action to be taken.
|
|
.\" NEXT FIGURE
|
|
.so figs/mbufrcv.nr
|
|
.\".so figs/mbufrcv.grn
|
|
.sh 1 "Receive"
|
|
.pp
|
|
This module reorders incoming TPDUs if necessary,
|
|
depacketizes data, passes it to the socket code module,
|
|
and determines when acknowledgments should be sent.
|
|
The function
|
|
\fItp_stash()\fR
|
|
takes an DT TPDU as an argument, and if the TPDU is not in
|
|
sequence, it saves the TPDU in a \fItp_rtc\fR structure in
|
|
a list, with the TPDUs
|
|
kept in order.
|
|
When the next expected TPDU arrives, the
|
|
list of out-of-order TPDUs is scanned for
|
|
more TPDUs in sequence, updating
|
|
a field in the pcb, \fItp_rcvnxt\fR which
|
|
always contains the sequence
|
|
number of
|
|
the next expected TPDU.
|
|
If an acknowledgment is to be generated
|
|
at any time, the value of tp_rcvnxt goes into the
|
|
\fIYR-TU-NR\fR\** field of the acknowledgment TPDU.
|
|
.(f
|
|
\**
|
|
This is the name used in ISO 8073 for the field
|
|
which indicates the sequence number of the next expected DT TPDU.
|
|
.)f
|
|
.pp
|
|
\fITp_stash()\fR returns true if an acknowledgment needs to be generated
|
|
immediately, false not.
|
|
The acknowledgment strategy is therefore implemented in this routine.
|
|
Acknowledgments may be generated for one or more of several reasons,
|
|
listed below.
|
|
\fITp_stash()\fR increments a counter for each of these reasons
|
|
for which an acknowledgment is generated, and a counter for TPDUs
|
|
that are not acknowledged immediately.
|
|
.ip "ACK_STRAT_EACH" 5
|
|
The acknowledgment strategy in use calls for acknowledging each
|
|
data packet with an AK TPDU.
|
|
.ip "ACK_STRAT_FULLWIN" 5
|
|
The acknowledgment strategy in use calls for acknowledging
|
|
upon receiving the DT TPDU that represents the upper window
|
|
edge of the last advertised window.
|
|
.ip "ACK_DUP" 5
|
|
A duplicate data TPDU was received.
|
|
.ip "ACK_REORDER" 5
|
|
A DT TPDU arrived in the window but out of order.
|
|
.ip "ACK_EOT" 5
|
|
A DT TPDU arrived, and it had the end-of-TSDU flag set.
|
|
.pp
|
|
Upon receipt of a DT TPDU that is in order, and upon reordering
|
|
DT TPDUs,
|
|
\fItp_stash()\fR
|
|
places the TSDUs into the socket's receive
|
|
socket buffer, \fIso->so_rcv\fR in mbuf chains, with
|
|
TSDUs delimited by mbufs of the \fIm_type\fR MT_EOT,
|
|
which is a new type with the ARGO kernel.
|
|
.CF
|
|
illustrates the structure of the receiving socket buffer used
|
|
for normal data.
|
|
.pp
|
|
A separate socket buffer, \fItpcb->tp_Xrcv\fR,
|
|
is used for
|
|
buffering expedited data.
|
|
Only one expedited data packet may reside in this buffer at a time
|
|
because the TP standard limits the size of the window on expedited flow
|
|
to be 1.
|
|
This means the data structures are straightforward;
|
|
there is no need to distinguish between separate TSDUs in this socket buffer.
|
|
.pp
|
|
Credit is determined
|
|
by dividing the total amount of available
|
|
space in the receive buffer
|
|
by the negotiated maximum TPDU size.
|
|
TP can often offer a larger credit than this if it uses
|
|
an average of the measured actual TPDU sizes.
|
|
This strategy was once an option in the ARGO kernel,
|
|
but it was removed because unless the actual TPDU size
|
|
is constant, it leads to reneging of credit,
|
|
retransmissions, and decreased performance.
|
|
It does not work well when there is any fluctuation in the sizes
|
|
of TPDUs and it carries the penalty of lengthening the critical path
|
|
of the TP entity.
|
|
.sh 1 "Major Data Structures and Types"
|
|
.pp
|
|
In addition to the types commonly used in the kernel,
|
|
such as
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l l l l.
|
|
+typedef+unsigned char+u_char;
|
|
+typedef+unsigned int+u_int;
|
|
+typedef+unsigned short+u_short;
|
|
.TE
|
|
\fR
|
|
.)b
|
|
TP uses the following types:
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l l l l.
|
|
+typedef+unsigned int+SeqNum
|
|
+typedef+unsigned short+RefNum;
|
|
+typedef+int+ProtoHook;
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.pp
|
|
Sequence numbers can be either 7 or 31 bits.
|
|
An unsigned integer is used in all cases, and the proper type
|
|
of arithmetic is performed with bit masks.
|
|
Reference numbers are 16 bits.
|
|
ProtoHook is the type of the procedures that are in switch
|
|
tables, which,
|
|
although they are not functions,
|
|
are declared \fIint\fR rather than \fIvoid\fR
|
|
to be consistent with the rest of the kernel.
|
|
.pp
|
|
The following structures are fundamental
|
|
types used throughout TP,
|
|
in addition to those already described in the
|
|
section,
|
|
"The Design of the Transport Entity".
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l s s s.
|
|
struct tp_ref {
|
|
.T&
|
|
l l l l.
|
|
+u_char+tpr_state;+/* REF_FROZEN...*/
|
|
+struct Ccallout+tpr_callout[N_CTIMERS];+/* C timers */
|
|
+struct Ecallout+tpr_calltodo;+/* E timers list */
|
|
+struct tp_pcb+*tpr_pcb;+/* --> PCB */
|
|
};
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
The reference structure is logically a part of the protocol
|
|
control block and it is linked to a pcb, but it may outlive
|
|
a pcb.
|
|
When a connection is dissolved, the pcb may be recycled
|
|
but the reference structure must remain until the reference
|
|
timer goes off.
|
|
The field \fItpr_state\fR takes the values
|
|
REF_FROZEN (a reference timer is ticking),
|
|
REF_OPEN (in use, has timers and an associated pcb),
|
|
REF_OPENING (has a pcb but no timers), and
|
|
REF_FREE (free to reallocate).
|
|
.pp
|
|
The TP protocol control block is too large to fit into
|
|
one mbuf structure so it comprises two structures
|
|
linked together, the
|
|
\fItp_pcb\fR structure and the.
|
|
\fItp_pcb_aux\fR structure.
|
|
The \fItp_pcb_aux\fR structure contains
|
|
items that are used less frequently than those in
|
|
the former structure, since each access to these
|
|
items requires a second pointer dereference.
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l s s s.
|
|
struct tp_pcb_aux {
|
|
.T&
|
|
l l l s.
|
|
+struct sockbuf+tpa_Xsnd;+/* for expedited data */
|
|
+struct sockbuf+tpa_Xrcv;+/* for expedited data */
|
|
+u_char +tpa_vers;+/* protocol version */
|
|
+u_char +tpa_peer_acktime;+/* to compute DT TPDU
|
|
+++retrans timer value */
|
|
+SeqNum+tpa_Xsndnxt;+/* seq # of
|
|
+++next XPD to send */
|
|
+SeqNum+tpa_Xuna;+/* seq # of
|
|
+++unacked XPD */
|
|
+SeqNum+tpa_Xrcvnxt;+/* next XPD seq #
|
|
+++expect to recv */
|
|
+/* addressing */
|
|
+u_short+tpa_domain;+/* domain AF_ISO,...*/
|
|
+u_short+tpa_fsuffixlen;+/* foreign suffix */
|
|
+u_char+tpa_fsuffix[MAX_TSAP_SEL_LEN];+
|
|
+u_short+tpa_lsuffixlen;+/* local suffix */
|
|
+u_char+tpa_lsuffix[MAX_TSAP_SEL_LEN];+
|
|
.T&
|
|
l s s s.
|
|
+/* AK subsequencing */
|
|
.T&
|
|
l l l s.
|
|
+u_short+tpa_s_subseq;+/* next subseq to send */
|
|
+u_short+tpa_r_subseq;+/* highest recv subseq */
|
|
};
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.pp
|
|
The major portion of the protocol control block is in the
|
|
\fItp_pcb\fR structure:
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(%);
|
|
l s s s.
|
|
struct tp_pcb {
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
.\" The next line sets the spacing for the table: 1+3 17+3 17+3 13+3
|
|
% % %
|
|
.\"456789 123456789- 123456789 123456-789 123456789 1234567890
|
|
.\"
|
|
%struct tp_ref%*tp_refp;%
|
|
.T&
|
|
l l l s.
|
|
%%/* reference structure */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%struct tp_pcb_aux%*tp_aux;%
|
|
.T&
|
|
l l l s.
|
|
%%/*rest of tpcb (auxiliary struct)*/%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%caddr_t%tp_npcb;%/* to ll pcb */
|
|
%struct nl_protosw%*tp_nlproto;%
|
|
.T&
|
|
l l l s.
|
|
% %/* domain-dependent routines */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%struct socket%*tp_sock;%/* back ptr */
|
|
.\" ***************************************
|
|
.T&
|
|
l s s s.
|
|
|
|
/* local and foreign reference numbers: */
|
|
.T&
|
|
l l l l.
|
|
%RefNum%tp_lref;%
|
|
%RefNum%tp_fref;%
|
|
.\" ***************************************
|
|
.T&
|
|
l s s s.
|
|
.\"456789 123456789 123456789 123456789 123456789 1234567890
|
|
|
|
/* Stuff for sequence space arithmetic:
|
|
* Maintaining 2 sequence spaces is a pain so we set these
|
|
* values once at connection establishment time. Sequence
|
|
* number arithmetic is a set of macros which uses these.
|
|
* Sequence numbers are stored as 32 bits.
|
|
* tp_seqmask tells which of the 32 bits is used.
|
|
* tp_seqibt is the lsb that is not used. When set,
|
|
* it indicates wraparound has occurred.
|
|
* tp_seqhalf is the value that is half the sequence space.
|
|
* (or half plus one).
|
|
*/
|
|
.T&
|
|
l l l l.
|
|
%u_int%tp_seqmask;%/* mask */
|
|
%u_int%tp_seqbit;%/* wraparound */
|
|
%u_int%tp_seqhalf;%/* half space */
|
|
.\" ***************************************
|
|
.T&
|
|
l s s s.
|
|
|
|
/* flags: values are defined in tp_user.h.
|
|
* Here we keep such info as which options
|
|
* are in use: checksum, extended format,
|
|
* flow control in class 2, etc.
|
|
* See tp(4p) man page.
|
|
*/
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%u_short%tp_state;%/* fsm */
|
|
%short%tp_retrans;%
|
|
.T&
|
|
l l l s.
|
|
% % /* # times to retransmit */%
|
|
.\" ***************************************
|
|
.T&
|
|
l s s s.
|
|
|
|
/* credit & sequencing info for SENDING: */
|
|
.T&
|
|
l l l s.
|
|
%u_short%tp_fcredit;%
|
|
% %/* remote real window */%
|
|
%u_short%tp_cong_win;%
|
|
% %/* remote congestion window */%
|
|
.\" ***************************************
|
|
%SeqNum%tp_snduna;%
|
|
.T&
|
|
l l l s.
|
|
% %/* seq # of lowest unacked DT */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%struct tp_rtc %*tp_snduna_rtc;%
|
|
.T&
|
|
l l l s.
|
|
% %/* ptr to mbufs containing lowest%
|
|
%% * unacked TPDUs sent so far%
|
|
%% */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%SeqNum%tp_sndhiwat;%
|
|
.T&
|
|
l l l s.
|
|
% %/* highest DT sent yet */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%struct tp_rtc%*tp_sndhiwat_rtc;%
|
|
.T&
|
|
l l l s.
|
|
% %/* ptr to mbufs containing the last%
|
|
%% * DT sent - this is the last item %
|
|
%% * on the list that starts%
|
|
%% * at tp_snduna_rtc%
|
|
%% */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%int %tp_Nwindow;%/* for perf. measmt */
|
|
.\" ***************************************
|
|
.T&
|
|
l s s s.
|
|
|
|
/* credit & sequencing info for RECEIVING: */
|
|
.\" ***************************************
|
|
.T&
|
|
l l l s.
|
|
%SeqNum%tp_sent_lcdt;%
|
|
%%/* cdt according to last AK sent */%
|
|
%SeqNum%tp_sent_uwe;%
|
|
% %/* upper window edge, according to%
|
|
%% * the last AK sent %
|
|
%% */*
|
|
%SeqNum%tp_sent_rcvnxt;%
|
|
% %/* rcvnxt, according to%
|
|
%% * the last AK sent%
|
|
%% */*
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%short%tp_lcredit;%/* local */
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%SeqNum%tp_rcvnxt;%
|
|
.T&
|
|
l l l s.
|
|
% %/* next DT seq# we expect to recv */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%struct tp_rtc%*tp_rcvnxt_rtc;%
|
|
.T&
|
|
l l l s.
|
|
% %/* ptr to mbufs containing unacked %
|
|
%% * DTs received out of order, and %
|
|
%% * which we haven't acknowledged%
|
|
%% */%
|
|
.\" ***************************************
|
|
.TE
|
|
.TS
|
|
tab(%);
|
|
l s s s.
|
|
/* Items kept in the aux structure: */
|
|
|
|
.\" ***************************************
|
|
.T&
|
|
l s s l.
|
|
#define tp_vers%tp_aux->tpa_vers
|
|
#define tp_peer_acktime%tp_aux->tpa_peer_acktime
|
|
#define tp_Xsnd%tp_aux->tpa_Xsnd
|
|
#define tp_Xrcv%tp_aux->tpa_Xrcv
|
|
#define tp_Xrcvnxt%tp_aux->tpa_Xrcvnxt
|
|
#define tp_Xsndnxt%tp_aux->tpa_Xsndnxt
|
|
#define tp_Xuna%tp_aux->tpa_Xuna
|
|
#define tp_domain%tp_aux->tpa_domain
|
|
#define tp_fsuffixlen%tp_aux->tpa_fsuffixlen
|
|
#define tp_fsuffix%tp_aux->tpa_fsuffix
|
|
#define tp_lsuffixlen%tp_aux->tpa_lsuffixlen
|
|
#define tp_lsuffix%tp_aux->tpa_lsuffix
|
|
#define tp_s_subseq%tp_aux->tpa_s_subseq
|
|
#define tp_r_subseq%tp_aux->tpa_r_subseq
|
|
.\" ***************************************
|
|
.T&
|
|
l s s s.
|
|
% % %
|
|
/* parameters per-connection controllable by user: */
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%struct%tp_conn_param%_tp_param;
|
|
% % %
|
|
.\" ***************************************
|
|
.T&
|
|
l s s l.
|
|
#define tp_Nretrans%_tp_param.p_Nretrans
|
|
#define tp_dr_ticks%_tp_param.p_dr_ticks
|
|
#define tp_cc_ticks%_tp_param.p_cc_ticks
|
|
#define tp_dt_ticks%_tp_param.p_dt_ticks
|
|
#define tp_xpd_ticks%_tp_param.p_x_ticks
|
|
#define tp_cr_ticks%_tp_param.p_cr_ticks
|
|
#define tp_keepalive_ticks%_tp_param.p_keepalive_ticks
|
|
#define tp_sendack_ticks%_tp_param.p_sendack_ticks
|
|
#define tp_refer_ticks%_tp_param.p_ref_ticks
|
|
#define tp_inact_ticks%_tp_param.p_inact_ticks
|
|
#define tp_xtd_format%_tp_param.p_xtd_format
|
|
#define tp_xpd_service%_tp_param.p_xpd_service
|
|
#define tp_ack_strat%_tp_param.p_ack_strat
|
|
#define tp_rx_strat%_tp_param.p_rx_strat
|
|
#define tp_use_checksum%_tp_param.p_use_checksum
|
|
#define tp_tpdusize%_tp_param.p_tpdusize
|
|
#define tp_class%_tp_param.p_class
|
|
#define tp_winsize%_tp_param.p_winsize
|
|
#define tp_netservice%_tp_param.p_netservice
|
|
#define tp_no_disc_indications%_tp_param.p_no_disc_indications
|
|
#define tp_dont_change_params%_tp_param.p_dont_change_params
|
|
.\" ***************************************
|
|
.TE
|
|
.\" ***************************************
|
|
.\" ***************************************
|
|
.\" ***************************************
|
|
.TS
|
|
tab(%);
|
|
l l l l.
|
|
.\" The next line sets the spacing for the table: 1+3 17+3 17+3 13+3
|
|
.\"456789 123456789- 123456789 123456-789 123456789 1234567890
|
|
.\"
|
|
.T&
|
|
l l l s.
|
|
%%/* log2(the negotiated max size) */%
|
|
.T&
|
|
l l l l.
|
|
%int%tp_l_tpdusize;%/* # bytes */
|
|
.\" ***************************************
|
|
%struct timeval%tp_rtt;%
|
|
.T&
|
|
l l l s.
|
|
% %/* smoothed avg round-trip time */%
|
|
%struct timeval%tp_rtv;%
|
|
% %/* std deviation of round-trip time */%
|
|
%struct timeval%tp_rttemit[ TP_RTT_NUM + 1 ];%
|
|
%%/* times that the last TP_RTT_NUM %
|
|
%% * DT_TPDUs were transmitted %
|
|
%% */%
|
|
.\" ***************************************
|
|
%unsigned % %
|
|
% tp_sendfcc:1,%/* shall next ack %
|
|
% %include flow control conf. param? */%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l s.
|
|
% tp_trace:1,%/* is this pcb being traced?%
|
|
%% * (not used yet) %
|
|
%% */%
|
|
.\" ***************************************
|
|
% tp_perf_on:1,%/* statistics being kept? */%
|
|
.\" ***************************************
|
|
% tp_reneged:1,%/* have we reneged on credit%
|
|
%% * since the last AK TPDU was sent? %
|
|
%% */%
|
|
% tp_decbit:4,%/* congestion experienced? */%
|
|
% tp_flags:8,%/* see #defines below */%
|
|
.\" ***************************************
|
|
% tp_unused:16;%%
|
|
.T&
|
|
l s s l.
|
|
#define TPF_XPD_PRESENT%TPFLAG_XPD_PRESENT
|
|
#define TPF_NLQOS_PDN%TPFLAG_NLQOS_PDN
|
|
#define TPF_PEER_ON_SAMENET%TPFLAG_PEER_ON_SAMENET
|
|
%%%
|
|
.\" ***************************************
|
|
.T&
|
|
l l l l.
|
|
%struct tp_pmeas%*tp_p_meas;%
|
|
.T&
|
|
l l l s.
|
|
% %/* ptr to mbuf to hold the perf.%
|
|
%% * statistics structure %
|
|
%% */%
|
|
.\" ***************************************
|
|
};
|
|
.TE
|
|
\fR
|
|
.\"
|
|
.\" end of tpcb structure (thank you)
|
|
.\"
|
|
.)b
|
|
.fi
|
|
.sh 1 "Sequence Number Arithmetic"
|
|
.pp
|
|
Sequence numbers in TP can be either 7 bits
|
|
(\*(lqnormal format\*(rq)
|
|
or 31 bits
|
|
(\*(lqextended format\*(rq).
|
|
Sequence numbers are unsigned integers,
|
|
regardless of their format.
|
|
Three fields are kept in the pcb to manage the sequence
|
|
number arithmetic:
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l l l l.
|
|
+u_int+tp_seqmask;+/* mask for seq space */
|
|
+u_int+tp_seqbit;+/* bit for seq # wraparound */
|
|
+u_int+tp_seqhalf;+/* half the seq space */
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
\fITp_seqmask\fR
|
|
is a bit mask indicating which bits are legitimate
|
|
for a sequence number of either format.
|
|
It takes the value 0x7f if 7-bit sequence numbers are in use,
|
|
and 0x7fffffff if 31-bit sequence numbers are in use.
|
|
\fITp_seqbit\fR
|
|
is the bit that becomes set when a sequence number wraps around
|
|
while being incremented.
|
|
Its value is 0x80 for normal format, 0x80000000 for extended format.
|
|
\fITp_seqhalf\fR
|
|
takes the value which is in the middle of the sequence space,
|
|
0x40 for normal format,
|
|
and
|
|
0x40000000 for extended format.
|
|
.(b
|
|
.nf
|
|
The macro
|
|
.fi
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l l l l.
|
|
SEQ(tpcb, x)
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
extracts a sequence number from the location
|
|
in which it is stored.
|
|
.pp
|
|
The macros
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l l s s l.
|
|
+SEQ_GT(tpcb, seq, t)+is seq > t?
|
|
+SEQ_GEQ(tpcb, seq, t)+is seq >= t?
|
|
+SEQ_LT(tpcb, seq, t)+is seq < t?
|
|
+SEQ_LEQ(tpcb, seq, t)+is seq <= t?
|
|
+SEQ_INC(tpcb, seq)+seq\+\+
|
|
+SEQ_DEC(tpcb, seq)+seq--
|
|
+SEQ_SUB(tpcb, seq, amt)+seq -= amt
|
|
+SEQ_ADD(tpcb, seq, amt)+seq \+= amt
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
perform the indicated comparisons and arithmetic
|
|
on their arguments.
|
|
.pp
|
|
An example of how these macros
|
|
are used is as follows.
|
|
To determine if a sequence
|
|
number \fIseq\fR is in a receive window
|
|
bounded by
|
|
\fIlwe\fR and \fIuwe\fR,
|
|
we define the
|
|
macro
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l l.
|
|
#define+IN_RWINDOW(tpcb, seq, lwe, uwe)\\
|
|
+( SEQ_GEQ(tpcb, seq, lwe) && SEQ_LT(tpcb, seq, uwe) )
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.sh 1 "TP Implementation Options"
|
|
.pp
|
|
The transport protocol specification leaves several
|
|
things to the discretion of the implementor,
|
|
some of which may affect the performance
|
|
of individual connections and
|
|
aggregate performance.
|
|
Wherever different strategies are likely to favor
|
|
the performance of
|
|
individual connections to the detriment of aggregate performance
|
|
or vice versa, the
|
|
various strategies are under the control of options via the
|
|
\fIgetsockopt()\fR and
|
|
\fIsetsockopt()\fR system calls (see the manual pages
|
|
\fIgetsockopt(2)\fR,
|
|
\fIsetsockopt(2)\fR
|
|
and
|
|
\fItp(4p)\fR
|
|
for details).
|
|
In some cases the preferred strategies differ for the different
|
|
subnetworks, so the strategies chosen will be determined
|
|
by the subnetwork in use.
|
|
.sh 2 "TPDU size"
|
|
.pp
|
|
The limitation of the maximum TPDU size to a power of two is
|
|
unfortunate in the LAN environment.
|
|
For example, if the maximum NSDU size is around 1500, as in the case of an
|
|
Ethernet,
|
|
using a maximum TPDU size of 1024 reduces
|
|
the possible throughput by approximately 30%.
|
|
TP negotiates a maximum TPDU size of 2048 and
|
|
generates TPDUs of size around 1500.
|
|
Obviously this works well only when the peer is known to be
|
|
using the same scheme (so that the peer
|
|
doesn't send TPDUs of size 2048 and cause its
|
|
network layer to fragment the TPDUs).
|
|
This is likely to be the case in a LAN where
|
|
all protocol entities are under the same administrative
|
|
control.
|
|
The maximum TPDU size negotiated is under the control of the user,
|
|
so
|
|
it is possible to prevent this scheme from being used
|
|
by default
|
|
when the peer is not on the same LAN, by
|
|
setting the \fItp.tpdusize\fR parameter in the ARGO directory service
|
|
file to
|
|
something less than the network's maximum transmission
|
|
unit.
|
|
.\"***********************************************************
|
|
.sh 2 "Congestion Window Strategy"
|
|
.pp
|
|
The congestion window strategy from the
|
|
DoD Internet
|
|
was adapted for use with TP.
|
|
The strategy is intended to minimize the
|
|
adverse effect
|
|
of transport's retransmission on an
|
|
already congested network.
|
|
.pp
|
|
A TP entity keeps two notions of the peer's window:
|
|
the real window, which is that advertised by the peer
|
|
in AK TPDUs, and the congestion window, which is a locally
|
|
controlled window.
|
|
TP uses the smaller of the two windows when transmitting.
|
|
The congestion window starts small, which keeps a
|
|
new connection from overloading the network with a sudden
|
|
burst of packets
|
|
immediately after connection establishement.
|
|
This is called \fIslow start\fR.
|
|
For each successful acknowledgment received, the congestion
|
|
window grows by one, until eventually the real window
|
|
is the one in use.
|
|
If a retransmission timer expires, the congestion window
|
|
is reset to size one.
|
|
.pp
|
|
The congestion window strategy is used for class 4 unless
|
|
the transport user requests that it not be used.
|
|
The slow start strategy is used for traffic over a PDN
|
|
unless
|
|
the transport user requests that it not be used.
|
|
Slow start is not used for traffic over a LAN unless
|
|
its use is requested by the transport user.
|
|
.\"***********************************************************
|
|
.sh 2 "Retransmission strategies"
|
|
.pp
|
|
A retransmission timer is invoked for each set of DT TPDUs
|
|
sent in one send operation (call to \fItp_send()\fR).
|
|
This set of packets is called the \fIsend window\fR for the purpose
|
|
of this discusssion.
|
|
.pp
|
|
The number of TPDUs
|
|
in a send window
|
|
depends on the remote credit and the amount of data
|
|
in the local send buffers.
|
|
When a retransmission timer goes off, the lower
|
|
window edge
|
|
is reevaluated but the upper window edge is not reevaluated.
|
|
.pp
|
|
There are several retransmission strategies implemented in
|
|
ARGO TP.
|
|
The choice of strategies is the user's, and is made with the
|
|
\fIsetsockopt()\fR system call.
|
|
The strategies are summarized here:
|
|
.ip "Retransmit LWE TPDU only:" 5
|
|
Only the TPDU representing the new lower window edge
|
|
is retransmitted.
|
|
This is the default retransmission strategy.
|
|
.ip "Retransmit whole send window:" 5
|
|
Retransmission begins with the new lower window edge
|
|
and continues up to the old upper window edge.
|
|
.pp
|
|
The value of the data retransmission timer
|
|
adapts to the average round trip time and the standard deviation of
|
|
the round trip time.
|
|
A round trip time is the time that passes between
|
|
the moment of a packet's first transmission and
|
|
the moment it is first acknowledged.
|
|
The average round trip time
|
|
is kept by the sending side of TP, using
|
|
a formula for
|
|
smoothing the average:
|
|
.(b
|
|
\fC
|
|
.TS
|
|
tab(+);
|
|
l l l l.
|
|
#define+TP_RTT_ALPHA+3
|
|
#define+TP_RTV_ALPHA+2
|
|
+++
|
|
#define+SMOOTH(alpha, old, new) \\
|
|
+(((new-old) >> alpha ) \+ (old) )
|
|
.TE
|
|
\fR
|
|
.)b
|
|
.lp
|
|
The times included in the average are chosen as follows.
|
|
The time of
|
|
each packet's initial transmission is kept (for the last
|
|
\fIN\fR packets, where \fIN\fR is a defined constant).
|
|
When an AK TPDU arrives, ARGO TP subtracts the initial transmission
|
|
time for the lowest unacknowledged sequence number that was
|
|
acknowledged by this AK TPDU from the current time,
|
|
and apply the resulting time to the average.
|
|
Hence, not all packets are included in this average,
|
|
which is as it should be since
|
|
the purpose of this measurement is
|
|
to find a good value for the retransmission timer.
|
|
.pp
|
|
Each time part of a window is retransmitted,
|
|
the retransmission timer for that window is increased.
|
|
This does not affect the retransmission timers for other windows.
|
|
.\"***********************************************************
|
|
.sh 2 "Acknowledgment strategies"
|
|
.pp
|
|
The transport protocol specification
|
|
requires acknowledgments to be sent immediately
|
|
upon receipt
|
|
of CC TPDUs (in class 4), XPD TPDUs, and DT TPDUs containing an
|
|
EOT marker, and at other times as required for flow control,
|
|
otherwise acknowledgments may be delayed.
|
|
In addition to the times when an acknowledgment is required,
|
|
ARGO TP transmits an AK TPDU whenever the user receives some data,
|
|
thereby increasing the size of the window.
|
|
For those times when
|
|
immediate acknowledgment is optional,
|
|
ARGO TP offers two acknowledgment strategies:
|
|
.ip " Acknowledge each TPDU" 10
|
|
Upon receipt of a DT TPDU and AK TPDU is sent.
|
|
.ip " Acknowledge full window" 10
|
|
Acknowledgment is issued
|
|
upon receipt of enough data to
|
|
consume the last advertised credit.
|
|
.pp
|
|
The latter strategy
|
|
requires a timer to trigger an acknowledgment
|
|
in case the peer doesn't send the entire window
|
|
quickly.
|
|
This timer is called the
|
|
\fIsendack timer\fR.
|
|
The upper bound on the value of this timer
|
|
is called the \fIlocal acknowledgment time\fR.
|
|
The local acknowledgment time may be "advertised" to the
|
|
peer during connection establishment, and the
|
|
peer may choose to use this value to
|
|
adjust its retransmission timers.
|
|
The ARGO TP entity advertises its local acknowledgment time
|
|
on a CR TPDU, but it is not
|
|
constrained by
|
|
the remote acknowledge time, should the peer
|
|
advertise it.
|
|
Instead,
|
|
ARGO TP adapts its sendack timer
|
|
to the behavior of the connection.
|
|
.pp
|
|
Under the assumption that the round trip time is
|
|
often
|
|
symmetric,
|
|
and lacking
|
|
a method to measure
|
|
the round trip time in the other direction,
|
|
ARGO TP uses the measured average round trip time
|
|
to adjust the the sendack timer.
|
|
.pp
|
|
The choice of strategies is made with the
|
|
\fIsetsockopt()\fR system call.
|
|
The default strategy is
|
|
to
|
|
delay acknowledgments until the most recently advertised window is filled.
|