Age | Commit message (Collapse) | Author |
|
* anders/diameter/sctp/OTP-10889:
Make unordered delivery configurable
|
|
Changing the default in the parent commit is possibly a bit dangerous,
even if the motivation still holds. Take a step back and make unordered
delivery a matter of configuration, without changing the default:
configuration is {unordered, boolean() | pos_integer()}, with false the
default, and N equivalent to OS =< N, where OS is the number of outbound
streams negotiated on the association in question.
A user can mess with this by configuring an sctp_default_send_param of
their own, but unordered sending is them from start, not only after the
second message reception.
|
|
* anders/diameter/sctp/OTP-10889:
Send unordered on all outbound diameter_sctp streams
Delay rotation of diameter_sctp outbound streams
Exercise unordered delivery in traffic suite
Use unordered delivery on a lone outbound stream in diameter_sctp
|
|
There's no reason for sending ordered since request handling is
concurrent: different processes handling incoming requests can't know in
which order they were received on the transport, and different processes
sending requests can't know the order in which they're sent.
|
|
For the same reason as unordered delivery is delayed in the grandparent
commit. Delivery is ordered only within a stream, so until a second
message is received from the peer, there's no guarantee that a second
outgoing request won't be received before the initial capablities
exchange message. Rotation begins upon reception of a second message
from the peer, messages being sent on stream 0 until then.
|
|
* anders/diameter/config_consistency/OTP-14555:
Let strict_mbit and incoming_maxlen be configured per transport
Let a service configure default transport options
Rename type evaluable -> eval
|
|
* anders/diameter/loopback_any/OTP-14544:
Use loopback/any config in examples suite
Handle loopback/any as local address in diameter_tcp/sctp
|
|
RFC 6733 say the below about head-of-line blocking and SCTP, the
suggestion of unordered sending being new compared to the RFC 3588.
Until now, all delivery in diameter_sctp has been ordered, and
roundrobin over available streams unless the user passes a stream
identifier in an outgoing diameter_packet record. This commit changes
this to use unordered delivery when there's only a single outbound
stream to choose from.
The special case at capabilities exchange is handled by only starting to
send unordered after the second message from the peer has been received.
(First message after capabilities exchange, as the RFC probably means.)
The special case at DPR isn't handled, since there's no knowing the
order in which a peer will answer: a node that sends DPR while it has
other requests outstanding can't expect that the latter will be answered
before DPR, even if delivery is ordered since incoming requests are
handled concurrently. If it wants a guarantee then it simply has to wait
for answers before sending DPR.
A user can force all delivery to be unordered by specifying
{sctp_default_send_params, #sctp_sndrcvinfo{flags = [unordered]}}
as a config option to diameter_sctp, but in this case there's no
handling of a request being sent directly after CEA since there's no
ordered flag to override the default.
RFC 6733:
2.1.1. SCTP Guidelines
Diameter messages SHOULD be mapped into SCTP streams in a way that
avoids head-of-the-line (HOL) blocking. Among different ways of
performing the mapping that fulfill this requirement it is
RECOMMENDED that a Diameter node send every Diameter message (request
or response) over stream zero with the unordered flag set. However,
Diameter nodes MAY select and implement other design alternatives for
avoiding HOL blocking such as using multiple streams with the
unordered flag cleared (as originally instructed in RFC 3588). On
the receiving side, a Diameter entity MUST be ready to receive
Diameter messages over any stream, and it is free to return responses
over a different stream. This way, both sides manage the available
streams in the sending direction, independently of the streams chosen
by the other side to send a particular Diameter message. These
messages can be out-of-order and belong to different Diameter
sessions.
Out-of-order delivery has special concerns during a connection
establishment and termination. When a connection is established, the
responder side sends a CEA message and moves to R-Open state as
specified in Section 5.6. If an application message is sent shortly
after the CEA and delivered out-of-order, the initiator side, still
in Wait-I-CEA state, will discard the application message and close
the connection. In order to avoid this race condition, the receiver
side SHOULD NOT use out-of-order delivery methods until the first
message has been received from the initiator, proving that it has
moved to I-Open state. To trigger such a message, the receiver side
could send a DWR immediately after sending a CEA. Upon reception of
the corresponding DWA, the receiver side should start using out-of-
order delivery methods to counter the HOL blocking.
Another race condition may occur when DPR and DPA messages are used.
Both DPR and DPA are small in size; thus, they may be delivered to
the peer faster than application messages when an out-of-order
delivery mechanism is used. Therefore, it is possible that a DPR/DPA
exchange completes while application messages are still in transit,
resulting in a loss of these messages. An implementation could
mitigate this race condition, for example, using timers, and wait for
a short period of time for pending application level messages to
arrive before proceeding to disconnect the transport connection.
Eventually, lost messages are handled by the retransmission mechanism
described in Section 5.5.4.
|
|
Export the old type as a synonym for backwards compatability. The name
evaluable is a bit too awkward.
|
|
The support is implied by documentation, but wasn't handled in code. Be
consistent in retrieving the address from the sock rather than the
configuration, and in accepting both ip and ifaddr for a local address.
|
|
* anders/diameter/transport/ERL-332:
Remove irrelevant comment
Add missing setopts after deferred diameter_{tcp,sctp} actions
|
|
|
|
Since the actions can request that a previously passive socket be made
active.
Missed in commits 636a7199 and 373cd07c.
|
|
* anders/diameter/transport/ERL-332: (35 commits)
Capitulate on SCTP vs sparc-sun-solaris2.10
Remove obsolete traffic testcase
Fix dialyzer warnings
Remove client/server string decode from traffic suite
Add diameter_sctp option packet
Add diameter_sctp send/recv callbacks
Let diameter_tcp send/recv callbacks deal in diameter_packet
Randomly select traffic testcases
Exercise diameter_tcp message callbacks in traffic suite
Exercise diameter_{tcp,sctp} sender in traffic suite
Remove upgrade from diameter_traffic
Add diameter_tcp send/recv callbacks
Make diameter_{tcp,sctp} sender configurable
Remove upgrade from diameter_sctp; tweak diameter_tcp to match
Fix incomprehensible dialyzer warning
Simplify acks to transport processes
Strip throttling callbacks from diameter_tcp
Deal with (another) SCTP association id quirk on Solaris
Use binary:copy/2 when generating largish data in test suites
Deal with SCTP association id quirk on Solaris
...
|
|
diameter_sctp.erl:292: Record construction #transport{parent::pid(),mode::{'accept',atom() | pid() | port() | {atom(),atom()}},active::'false',recv::'true',os::0,packet::'true',message_cb::'undefined',send::'false'} violates the declared type of field message_cb::'false' | fun() | maybe_improper_list(fun() | maybe_improper_list(any(),[any()]) | {atom(),atom(),[any()]},[any()]) | {atom(),atom(),[any()]}
diameter_sctp.erl:302: Record construction #transport{mode::{'accept',atom() | pid() | port() | {atom(),atom()}},active::'false',recv::'true',os::0,packet::'true',message_cb::'undefined',send::'false'} violates the declared type of field message_cb::'false' | fun() | maybe_improper_list(fun() | maybe_improper_list(any(),[any()]) | {atom(),atom(),[any()]},[any()]) | {atom(),atom(),[any()]}
|
|
To determine the wrapping of messages passed to recv callbacks and into
diameter. The default passing of the input stream in transport_data is
probably of no practical use, but has been set since time immemorial.
|
|
Corresponding to diameter_tcp callbacks a few commits back. Exercise the
callbacks in the traffic suite.
|
|
With sends still from the receiving process by default, since changing
the default behaviour may well have negative effects. A separate sender
probably implies a greater need for some form of load regulation for
one, since a blocking send would no longer imply that incoming messages
are no longer recevied. Dealing with this could result in the same
deadlock that the sending process intends to avoid, but the user should
be in control over how/when incoming traffic is regulated.
|
|
Added in commit 2afd1fe5. Only rename variables in diameter_tcp, no
functional change.
|
|
Shutdown events have been seen to get a different association id.
For example, first incoming message with association id = 0:
+ {trace_ts,<6421.268.0>,call,
{diameter_sctp,handle_info,
[{sctp,#Port<6421.2588>,
{10,67,16,179},
44159,
{[{sctp_sndrcvinfo,0,0,[],0,0,0,269950872,269950872,0}],
<<1,0,0,156,128,0,1,1,0,0,0,0,6,193,40,137,6,193,40,137,0,0,
1,8,64,0,0,30,67,45,49,51,52,50,49,55,52,52,49,46,101,114,
108,97,110,103,46,111,114,103,0,0,0,0,1,40,64,0,0,18,101,
114,108,97,110,103,46,111,114,103,0,0,0,0,1,1,64,0,0,14,0,
1,127,0,0,1,0,0,0,0,1,10,64,0,0,12,0,0,48,57,0,0,1,13,0,0,
0,20,79,84,80,47,100,105,97,109,101,116,101,114,0,0,1,22,
64,0,0,12,0,0,0,1,0,0,1,2,64,0,0,12,0,0,0,0,0,0,1,3,64,0,0,
12,0,0,0,3>>}},
{transport,<6421.252.0>,accept,#Port<6421.2588>,true,undefined,
{32,32},
0,undefined}]},
{1493,21505,577938}}
Later, a shutdown event with association id 1536:
+ {trace_ts,<6421.268.0>,call,
{diameter_sctp,handle_info,
[{sctp,#Port<6421.2588>,
{10,67,16,179},
44159,
{[],{sctp_shutdown_event,1536}}},
{transport,<6421.252.0>,accept,#Port<6421.2588>,0,undefined,
{32,32},
2,<6421.304.0>}]},
{1493,21505,746929}}
Both this and the grandparent commit are on this:
$ uname -a
SunOS beren 5.10 Generic_118833-33 sun4v sparc SUNW,Netra-T2000
|
|
In particular, that the association id received in messages on a
one-to-one socket after peeloff may be different from the id received on
the listen socket at comm_up.
This seems odd, since it's then not possible to send until the id is
discovered by reception of an SCTP message containing it, but it's
unclear if this is a bug or a feature, or if it's specific to certain
platforms. Treat it as a feature in this commit, and get the association
id as mentioned, an incoming CER being expected before anything is sent.
Commit da3e5d67 has more history.
|
|
Both diameter_tcp and diameter_sctp are susceptible to deadlock since a
peer that blocks send also prevents additional messages from being
received. Send from a process that's paired with the transport process
to avoid this. Use the existing monitor process in the TCP case, add one
in the SCTP case.
This has been the reason for many sporadic testcase failures, mostly in
diameter_traffic_SUITE.
|
|
|
|
|
|
Commit 5ca5fb71 ensured that they were closed immediately at transport
removal, but in so doing broke their closing at stop service completely,
by removing the timer that caused sockets to be closed even belatedly.
Monitor on the service process to make it happen.
This could still be improved, since stop_service listening ports aren't
closed until after the service process has died. They could be closed
earlier in the case of stop_service.
|
|
The transport interface documented in diameter_transport(3) is used to
start/stop accepting/connecting transport processes: they're started
with a function call, and told to die with their parent process. In the
accepting case, both diameter_tcp and diameter_sctp start a listening
process when the first accepting transport is started. However, there's
no way for a listening process to find out that that it should stop
listening when transport configuration is removed.
Both diameter_tcp and diameter_sctp have used a timer to terminate the
listening process after all existing accepting processes have died as a
consequence of transport removal. The problem with this is that nothing
stops a new client from connecting before this, and also that no new
transport can succeed in opening the same listening port (eg.
reconfiguration) until the old listener dies.
This commit solves the problem by adding diameter_reg:subscribe/2, to
allow callers to subscribe to messages about added/removed associations.
A call to diameter:add_transport/2 results in a new child process that
registers a term that a listening process subscribes to. Transport
removal results in the death of the child, and the resulting
notification to the listener causes the latter to close its socket and
terminate.
This is still an internal interface, but the subscription mechanism
should probably be made external (eg. a diameter:subscribe/1 that can
be used to subscribe to specified messages), so that transport modules
other than diameter's own can make use of it. There is no support for
soft upgrade.
|
|
Record field types have been modified due to commit 8ce35b2:
"Take out automatic insertion of 'undefined' from typed record fields".
|
|
The diffs are all about adapting to the OTP 18 time interface. The code
was previously backwards compatible, falling back on the erlang:now/0 if
erlang:monotonic_time/0 is unavailable, but this was seen to be a bad
thing in commit 9c0f2f2c. Use of erlang:now/0 is now removed.
|
|
By doing away with more wrapping that the parent commit started to
remove.
|
|
OTP-12845
* bruce/change-license:
fix errors caused by changed line numbers
Change license text to APLv2
|
|
A listener process in diameter_sctp starts accepting transport processes
as required, either as associations are established or as diameter asks
for a processes to be started. Since this can happen in any order, the
listener maintains two queues: one for processes that diameter has
requested and which are waiting to be given an association, another for
processes that have been started to become owners of an association but
are waiting for diameter to request them. Only one queue at a time is
non-empty. The first queue's length is bounded by the number of
accepting processes configured as pool_size. Entries in the second queue
are short-lived since diameter starts a replacement transport process
whenever an existing one dies or communicates that it has an
association.
The two queues were previously implemented in an ets ordered_set, whose
keys were the pid() of transport processes. Removing an element from the
queue was then done with ets:first/1. The problem with this it's not
really a queue: there's no guarantee that pid-ordering is the same as
the order in which processes are started. If it isn't then it's possible
that an established association never be given to diameter as a
transport process if there's always a newer association whose pid sorts
first. This isn't a problem in practice since it would require new
associations to be established faster than diameter starts transport
processes, but redo the implementation as a queue, with strict FIFO
semantics.
|
|
The changes in some of the previous commits assume application restart.
|
|
Don't pass an association id that's no longer used.
|
|
In particular, don't give the accepting transport process the listening
socket. It was used to match the initial sctp message received in a
peeloff message, but replace the socket in the forwarded message
instead.
|
|
The existing code was a remnant of the pre-peeloff implementation.
There's no need to close anything but the whole socket.
|
|
Listener death should have no effect on a peeled off association.
|
|
Forwarding an sctp message from the listener process at the same time
that the controlling process is changed means there's no guarantee that
the message order will be preserved. Selectively receive the peeloff
message before entering the gen_server loop to ensure the order is
preserved.
|
|
This is not the case under Solaris for one: successive
associations can receive the same association id as a result of peeloff,
the id only being unique for the controlling port, not for the listening
port as is the case under Linux for example. This made for many failures
in the diameter test suites, the traffic suite in particular.
Peeloff in diameter_sctp was introduced in 9a671bf0, before which the
assumption was fine since it was the listening process that owned all
associations. (Which obviously had other drawbacks.) Other remnants of
the pre-peeloff implementation have also been removed: that the listener
process might receive a message on a socket after peeloff for one.
Peeloff in gen_sctp became available in commit 067cfe79, after the
original implementation of diameter_sctp.
This is trace on the unpatched code showing id reuse under Solaris:
+ {trace_ts,<0.103.0>,call,
{diameter_sctp,handle_info,
[{sctp,#Port<0.1625>,
{127,0,0,1},
35904,
{[],{sctp_assoc_change,comm_up,0,32,32,1}}},
{listener,#Ref<0.0.1.948>,#Port<0.1625>,4,
57384,
{-4,61481},
#Ref<0.0.8.12>,
[]}]},
{1432,458752,612168}}
+ {trace_ts,<0.103.0>,call,
{diameter_sctp,handle_info,
[{sctp,#Port<0.1625>,
{127,0,0,1},
35905,
{[],{sctp_assoc_change,comm_up,0,32,32,1}}},
{listener,#Ref<0.0.1.948>,#Port<0.1625>,4,
57384,
{-3,61481},
#Ref<0.0.8.12>,
[]}]},
{1432,458752,613042}}
The result was this, when the second association was incorrectly
forwarded to the first association's controlling process:
** {function_clause,
[{diameter_sctp,transition,
[{peeloff,#Port<0.1635>,
{sctp,#Port<0.1625>,
{127,0,0,1},
35892,
{[],{sctp_assoc_change,comm_up,0,32,32,1}}},
[]},
{transport,<0.107.0>,accept,#Port<0.1634>,1,undefined,{32,32},0}],
[{file,"transport/diameter_sctp.erl"},{line,561}]},
{diameter_sctp,t,2,[{file,"transport/diameter_sctp.erl"},{line,549}]},
{diameter_sctp,handle_info,2,
[{file,"transport/diameter_sctp.erl"},{line,397}]},
{gen_server,try_dispatch,4,[{file,"gen_server.erl"},{line,614}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,680}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,238}]}]}
|
|
|
|
Commit 4b691d8d made it possible for accepting transport processes to be
started concurrently, and commit 77c1b162 adapted diameter_sctp to this,
but missed that the publication of the listener process in diameter_reg
has to precede the return of its start function. As a result, concurrent
starts could result in multiple listener processes.
|
|
In particular, deal with the deprecation of erlang:now/0 in OTP 18. Be
backwards compatible with older releases: the new api is only used when
available.
The test suites have not been modified.
|
|
Commit 24993fc2 modified the state even in the case that the new
pool_size option the change was introduced to support was not used.
Doing so made downgrade impossible since old code would not be prepared
for the modified state. Retain a compatible state, so that simple code
replacement is enough.
|
|
Commit 9a671bf0 removed the need for diameter_sctp to send outgoing
messages through the listening process. That was prior to R5B02, so the
clause isn't need for any upgrade case.
|
|
In particular, that starts for the same transport reference can now be
concurrent. Looking up a listener process and starting a new one if not
found did handle this (more than one process could find no listener),
and diameter_sctp assumed there could only be one transport process
waiting for an association.
|
|
Introduced in commit ed6395a6. The {stream, Id} transport_data set upon
reception is passed back to us by default when receiving the answer to a
request message, so even capabilities exchange failed.
|
|
OTP-10229 (commit c4592b69) added these function to give access to all
addresses on a multihomed endpoint, their singular siblings not
returning anything useful in this case.
This fixes {accept, Match} config, which matches peer addresses against
configured addresses or regexps to decide whether or not a newly
established association should be retained. The functionality was added
in OTP-10893 (commit 9bbf27eb) but predated OTP-10229 by a few months.
It also fixes the addresses shown for SCTP associations in
diameter:service_info/2 output.
|
|
* anders/diameter/17.0_release/OTP-11605:
vsn -> 1.6
Remove upgrade-related code
Update appup for 17.0
Avoid type gen_sctp:open_option() until it actually exists
|
|
No longer needed to update code in runtime since the emulator is
restarted at a major release.
|
|
The type's existence is the subject of OTP-11139, which has been
gathering dust since R16B.
http://erlang.org/pipermail/erlang-bugs/2013-September/003765.html
|
|
The module uses the transport_data field of record diameter_packet to
communicate the stream on which the an incoming message is received and
on which an outgoing message should be sent, the previous interface
being that both are communicated as a tuple of the form {stream, Id}.
However, since diameter retains the value of an incoming request's
transport_data unless the corresponding answer message specifies
otherwise, the behaviour in this case is to send an answer on the
outbound stream with the same identifier as the that of the inbound
stream on which the request was received. If the inbound stream id is
greater than or equal to the number of outbound streams then this is
guaranteed to fail, causing the transport process in question to
terminate. There is no relationship between inbound and outbound stream
identifiers so diameter_sctp's imposition of one is simply wrong.
Outbound stream ids are now communicated with a different tuple:
{outstream, Id}, interpreted modulo the number of outbound streams.
Thus, retention of an inbound request's transport_data has no effect on
the selection of an outbound stream.
The change in interface is not strictly backwards compatible because of
the new atom for the outbound stream. However, as there is currently no
documented way of obtaining the available number of outbound streams for
a peer connection, there is no way for a client to have known the range
of ids from which it could reliably have chosen with the previous
interface, so any setting of the outbound stream has probably been
unintentional. Not explicitly specifying an outbound stream now results
in a round-robin selection.
|