Age | Commit message (Collapse) | Author |
|
|
|
|
|
Each service process maintains a dictionary of peers, mapping an
application alias to a {pid(), #diameter_caps{}} list of connected
peers. These lists are potentially large, peers were appended to the end
of the list for no particular reason, and these long lists were
constructed/deconstructed when filtering them for pick_peer callbacks.
Many simultaneous outgoing request could then slow the VM to a crawl,
with many scheduled processes mired in list manipulation.
The pseudo-dicts are now replaced by plain ets tables. The reason for
them was (once upon a time) to have an interface interchangeable with a
plain dict for debugging purposes, but strict swapablity hasn't been the
case for some time now, and in practice a swap has never taken place.
Additional tables mapping Origin-Host/Realm have also been introduced,
to minimize the size of the peers lists when peers are filtered on
host/realm. For example, a filter like
{any, [{all, [realm, host]}, realm]}
is probably a very common case: preferring a Destination-Realm/Host
match before falling back on Destination-Realm alone. This is now more
efficiently (but not equivalently) expressed as
{first, [{all, [realm, host]}, realm]}
to stop the search when the best match is made, and extracts peers from
host/realm tables instead of searching through the list of all peers
supporting the application in question. The code to try and start with a
lookup isn't exhaustive, and the 'any' filter is still as inefficient as
previously.
|
|
|
|
There are differing opinions on whether or not reception of an arbitrary
AVP setting the M-bit is an error. 1.3.4 of RFC 6733 says this about
how an existing Diameter application may be modified:
o The M-bit allows the sender to indicate to the receiver whether or
not understanding the semantics of an AVP and its content is
mandatory. If the M-bit is set by the sender and the receiver
does not understand the AVP or the values carried within that AVP,
then a failure is generated (see Section 7).
It is the decision of the protocol designer when to develop a new
Diameter application rather than extending Diameter in other ways.
However, a new Diameter application MUST be created when one or more
of the following criteria are met:
M-bit Setting
An AVP with the M-bit in the MUST column of the AVP flag table is
added to an existing Command/Application. An AVP with the M-bit
in the MAY column of the AVP flag table is added to an existing
Command/Application.
The point here is presumably interoperability: that the command grammar
should specify explicitly what mandatory AVPs much be understood, and
that anything more is an error.
On the other hand, 3.2 says thus about command grammars:
avp-name = avp-spec / "AVP"
; The string "AVP" stands for *any* arbitrary AVP
; Name, not otherwise listed in that Command Code
; definition. The inclusion of this string
; is recommended for all CCFs to allow for
; extensibility.
This renders 1.3.4 pointless unless "*any* AVP" is qualified by "not
setting the M-bit", since the sender can effectively violate 1.3.4
without this necessitating an error at the receiver. If clients add
arbitrary AVPs setting the M-bit then request handling becomes more
implementation-dependent.
The current interpretation in diameter is strict: if a command grammar
doesn't explicitly allow an AVP setting the M-bit then reception of such
an AVP is regarded as an error. The strict_mbit option now allows this
behaviour to be changed, false turning all responsibility for the M-bit
over to the user.
|
|
|
|
This has had a hugely negative impact on performance when decoding
messages containing many AVP: each decode of an AVP having variable
arity computed the length of the list of previously decoded AVPs when
checking that the allowed arity was not exceeded, even if the allowed
arity was infinite, making for O(n^2) cost. Here are some execution
times, for diameter_codec:decode/2 on a representative message with n
integer AVPs in the Common application (on the host at hand):
Before After
------- ---------
n = 1K 5 ms 2 ms
n = 10K 500 ms 25 ms
n = 100K 75 sec 225 ms
n = 1M 2.6 sec
Note the nearly linear increase following the change.
Remove the dire documentation warning for incoming_maxlen as a
consequence. It can still be useful to set, but not doing so won't have
the same consequences as previously.
|
|
The warning report was removed in commit 00584303.
|
|
|
|
|
|
|
|
|
|
|
|
As for the port number in the parent commit, a FQDN can't be arbitrarily
long, at most 255 octets. Make decode fail if it's more.
|
|
To bound the length of incoming messages that will be decoded. A message
longer than the specified number of bytes is discarded. An
incoming_maxlen_exceeded counter is incremented to make note of the
occurrence.
The motivation is to prevent a sufficiently malicious peer from
generating significant load by sending long messages with many AVPs for
diameter to decode. The 24-bit message length header accomodates
(16#FFFFFF - 20) div 12 = 1398099
Unsigned32 AVPs for example, which the current record-valued decode is
too slow with in practice. A bound of 16#FFFF bytes allows for 5461
small AVPs, which is probably more than enough for the majority of
applications, but the default is the full 16#FFFFFF.
|
|
|
|
* anders/diameter/dpr/OTP-12609:
Discard incoming/outgoing requests after incoming DPR
Add transport_opt() dpr_timeout
Be lenient with errors in incoming DPR
|
|
* anders/diameter/string_decode/OTP-11952:
Let examples override default service options
Set {restrict_connections, false} in example server
Set {string_decode, false} in examples
Test {string_decode, false} in traffic suite
Add service_opt() string_decode
Strip potentially large terms when sending outgoing Diameter messages
Improve language consistency in diameter(1)
|
|
To control whether stringish Diameter types are decoded to string or
left as binary. The motivation is the same as in the parent commit: to
avoid large strings being copied when incoming Diameter messages are
passed between processes; or *if* in the case of messages destined for
handle_request and handle_answer callbacks, since these are decoded in
the dedicated processes that the callbacks take place in. It would be
possible to do something about other messages without requiring an
option, but disabling the decode is the most effective.
The value is a boolean(), true being the default for backwards
compatibility. Setting false causes both diameter_caps records and
decoded messages to contain binary() in relevant places that previously
had string(): diameter_app(3) callbacks need to be prepared for the
change.
The Diameter types affected are OctetString and the derived types that
can contain arbitrarily large values: OctetString, UTF8String,
DiameterIdentity, DiameterURI, IPFilterRule, and QoSFilterRule. Time and
Address are unaffected.
The DiameterURI decode has been redone using re(3), which both
simplifies and does away with a vulnerability resulting from the
conversion of arbitrary strings to atom.
The solution continues the use and abuse of the process dictionary for
encode/decode purposes, last seen in commit 0f9cdba.
|
|
To cause a peer connection to be closed following an outgoing DPA, in
case the peer fails to do so. It is the recipient of DPA that should
close the connection according to RFC 6733.
|
|
* anders/diameter/dpr/OTP-12542:
Discard CER or DWR sent with diameter:call/4
Allow DPR to be sent with diameter:call/4
Add transport_opt() dpa_timeout
Add testcase for sending DPR with diameter:call/4
|
|
To make the default DPA timeout configurable. The timeout say how many
milliseconds to wait for DPA in response to an outgoing DPR before
terminating the transport process regardless.
|
|
Akin to commit 85d44b58.
|
|
In particular, do away with unnecessary articles in the first sentence
of item lists.
|
|
Transport processes are started by diameter one at a time. In the
listening case, a transport process accepts a connection, tells the
peer_fsm process, which tells its watchdog process, which tells its
service process, which then starts a new watchdog, which starts a new
peer_fsm, which starts a new transport process, which (finally) goes
about accepting another connection. In other words, not particularly
aggressive in accepting new connections. This behaviour doesn't do
particularly well with a large number of concurrent connections: with
TCP and 250 connecting peers we see connections being refused.
This commit adds the possibilty of configuring a pool of accepting
processes, by way of a new transport option, pool_size. Instead of
diameter:add_transport/2 starting just a single process, it now starts
the configured number, so that instead of a single process waiting for a
connection there's now a pool.
The option is even available for connecting processes, which provides an
alternate to adding multiple transports when multiple connections to the
same peer are required. In practice this also means configuring
{restrict_connections, false}: this is not implicit.
For backwards compatibility, the form of
diameter:service_info(_,transport) differs in the connecting case,
depending on whether or not pool_size is configured.
Note that transport processes for the same transport_ref() can be
started concurrently when pool_size > 1. This places additional
requirements on diameter_{tcp,sctp}, that will be dealt with in a
subsequent commit.
|
|
|
|
The order of peers presented to a diameter_app(3) pick_peer callback has
previously not been documented, but there are use cases that are
simplified by an ordering. For example, consider preferring a direct
connection to a specified Destination-Host/Realm to any host in the
realm. The implementation previously treated this as a special case by
placing matching hosts at the head of the peers list, but the
documentation made no guarantees. Now present peers in match-order, so
that the desired sorting is the result of the following filter.
{any, [{all, [host, realm]}, realm]}
The implementation is not backwards compatible in the sense that a realm
filter alone is no longer equivalent in this case. However, as stated,
the documentation never made any guarantees regarding the sorting.
|
|
|
|
That dictionaries need to be recompiled, which is the case whenever
diameter_gen.hrl is modified.
|
|
|
|
* anders/diameter/17.1/OTP-11943:
Update appup for OTP-11946, OTP-11936: 5014, Failed-AVP decode
Update appup for OTP-11938: terminate watchdog after DPR reception
Update appup for OTP-11721: log and counter hardening
Update appup for OTP-11937: counters
Update appup for OTP-11901: diameter_sctp function_clause
Update appup for OTP-11934: watchdog process leak
Update appup for OTP-11893: request table leak
Update appup for OTP-11891: result code counters for CEA/DWA/DPA
vsn -> 1.7
Fix broken release note for diameter-1.4.4
|
|
Those were bug fixes, not known issues.
|
|
In the same vein as commit 00584303, to avoid logging traffic-related
happenings.
Not that the value in diameter.hrl is just documentation: the value is
set explicitly when diameter:start_service/2 creates diameter_app
records.
|
|
|
|
* anders/diameter/17.0_release/OTP-11605:
Move info modules into own subdirectory
Include compiler and info modules in app file
Remove unused diameter_dbg:log/4
Remove case expecting a pre-R16B return value from os:type/1
Fix doc typo: required -> requires
Remove release note unrelated to functionality
|
|
|
|
|
|
* anders/diameter/doc/OTP-11583:
Correct doc on the setting of Origin-State-Id
|
|
It was incorrectly stated that the AVP would be set in an outgoing
DPR/DPA.
|
|
* anders/diameter/sctp_streams/OTP-11593:
Change interface for communicating outbound stream id to diameter_sctp
|
|
* anders/diameter/undefined_group/OTP-11561:
Ensure that Grouped AVP's are fully defined in dictionaries
Don't format diameter_make:codec/2 errors
Compiler suite fix
|
|
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.
|
|
Instead, add diameter_make:format_error/1 to allow the caller to format
if desired, which is what applications like compiler and yecc do. Use
this to check that the expected error is the one actually generated in
the compiler suite.
|
|
The R16B03 release
Conflicts:
lib/sasl/vsn.mk
|
|
|
|
|
|
|
|
|
|
|
|
|