aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diameter')
-rwxr-xr-xlib/diameter/bin/diameterc30
-rw-r--r--lib/diameter/doc/src/diameter.xml78
-rw-r--r--lib/diameter/doc/src/diameter_app.xml4
-rw-r--r--lib/diameter/doc/src/diameter_codec.xml6
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml2
-rw-r--r--lib/diameter/doc/src/diameter_intro.xml4
-rw-r--r--lib/diameter/doc/src/diameter_make.xml94
-rw-r--r--lib/diameter/doc/src/diameter_sctp.xml2
-rw-r--r--lib/diameter/doc/src/diameter_soc_rfc6733.xml2
-rw-r--r--lib/diameter/doc/src/diameterc.xml (renamed from lib/diameter/doc/src/diameter_compile.xml)6
-rw-r--r--lib/diameter/doc/src/files.mk2
-rw-r--r--lib/diameter/doc/src/ref_man.xml2
-rw-r--r--lib/diameter/doc/src/seealso.ent4
-rw-r--r--lib/diameter/doc/standard/rfc7068.txt1627
-rw-r--r--lib/diameter/doc/standard/rfc7075.txt563
-rw-r--r--lib/diameter/examples/dict/.gitignore2
-rw-r--r--lib/diameter/examples/dict/GNUmakefile60
-rw-r--r--lib/diameter/examples/dict/depend.sed43
-rw-r--r--lib/diameter/examples/dict/rfc4004_mip.dia4
-rw-r--r--lib/diameter/examples/dict/rfc4005_nas.dia4
-rw-r--r--lib/diameter/examples/dict/rfc4006_cc.dia4
-rw-r--r--lib/diameter/examples/dict/rfc4072_eap.dia4
-rw-r--r--lib/diameter/examples/dict/rfc4590_digest.dia2
-rw-r--r--lib/diameter/examples/dict/rfc4740_sip.dia4
-rw-r--r--lib/diameter/src/base/diameter.erl2
-rw-r--r--lib/diameter/src/base/diameter_config.erl4
-rw-r--r--lib/diameter/src/base/diameter_service.erl17
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl2
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl548
-rw-r--r--lib/diameter/src/compiler/diameter_dict_util.erl7
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl245
-rw-r--r--lib/diameter/src/diameter.appup.src31
-rw-r--r--lib/diameter/test/diameter_codec_test.erl6
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl162
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl2
-rw-r--r--lib/diameter/vsn.mk2
36 files changed, 3128 insertions, 453 deletions
diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc
index 2f5834d359..d31f341c36 100755
--- a/lib/diameter/bin/diameterc
+++ b/lib/diameter/bin/diameterc
@@ -50,13 +50,10 @@ usage() ->
" -i dir = set an include directory for inherited beams~n"
" -E = no .erl output~n"
" -H = no .hrl output~n"
- " -d = write intermediate files (.spec and .forms)~n",
+ " -d = write intermediate files (.D and .F)~n",
[?MODULE]).
main(Args) ->
- %% Add the ebin directory relative to the script path.
- BinDir = filename:dirname(escript:script_name()),
- code:add_path(filename:join([BinDir, "..", "ebin"])),
halt(gen(Args)).
gen(Args) ->
@@ -72,15 +69,12 @@ gen(Args) ->
1
end.
-compile(#argv{file = File, options = Opts} = A) ->
- try diameter_dict_util:parse({path, File}, Opts) of
- {ok, Spec} ->
- maybe_output(A, Spec, Opts, spec), %% the spec file
- maybe_output(A, Spec, Opts, erl), %% the erl file
- maybe_output(A, Spec, Opts, hrl), %% The hrl file
+compile(#argv{file = File, options = Opts, output = Out}) ->
+ try diameter_make:codec({path, File}, Opts ++ Out) of
+ ok ->
0;
{error, Reason} ->
- error_msg(diameter_dict_util:format_error(Reason), []),
+ error_msg(Reason, []),
1
catch
error: Reason ->
@@ -88,10 +82,6 @@ compile(#argv{file = File, options = Opts} = A) ->
2
end.
-maybe_output(#argv{file = File, output = Output}, Spec, Opts, Mode) ->
- lists:member(Mode, Output)
- andalso diameter_codegen:from_dict(File, Spec, Opts, Mode).
-
error_msg({Fmt, Args}) ->
error_msg(Fmt, Args).
@@ -119,8 +109,9 @@ arg(["-o", Dir | Args], #argv{options = Opts} = A) ->
true = dir_exists(Dir),
arg(Args, A#argv{options = [{outdir, Dir} | Opts]});
-arg(["-i", Dir | Args], #argv{options = Opts} = A) ->
- arg(Args, A#argv{options = Opts ++ [{include, Dir}]});
+arg(["-i", Dir | Args], #argv{} = A) ->
+ code:add_patha(Dir), %% Set path here instead of passing an include
+ arg(Args, A); %% option so it's set before calling diameter_make.
arg(["--name", Name | Args], #argv{options = Opts} = A) ->
arg(Args, A#argv{options = [{name, Name} | Opts]});
@@ -137,9 +128,8 @@ arg(["-E" | Args], #argv{output = Output} = A) ->
arg(["-H" | Args], #argv{output = Output} = A) ->
arg(Args, A#argv{output = lists:delete(hrl, Output)});
-arg(["-d" | Args], #argv{options = Opts, output = Output} = A) ->
- arg(Args, A#argv{options = [debug | Opts],
- output = [spec | Output]});
+arg(["-d" | Args], #argv{output = Output} = A) ->
+ arg(Args, A#argv{output = [parse, forms | Output -- [parse, forms]]});
arg([[$- = M, C, H | T] | Args], A) %% clustered options
when C /= $i, C /= $o, C /= $- ->
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index f6b1f75230..7db67d932f 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -575,7 +575,7 @@ The RFC 3539 watchdog state machine has
transitioned into (<c>up</c>) or out of (<c>down</c>) the OKAY
state.
If a <c>#diameter_packet{}</c> is present in an <c>up</c> event
-then there has been a capabilties exchange on a newly established
+then there has been a capabilities exchange on a newly established
transport connection and the record contains the received CER or CEA.
Otherwise a connection has reestablished without the loss or
connectivity.</p>
@@ -584,7 +584,7 @@ connectivity.</p>
Note that a single <c>up</c> or <c>down</c> event for a given peer
corresponds to multiple &app_peer_up; or &app_peer_down;
callbacks, one for each of the Diameter applications negotiated during
-capablilities exchange.
+capabilities exchange.
That is, the event communicates connectivity with the
peer as a whole while the callbacks communicate connectivity with
respect to individual Diameter applications.</p>
@@ -599,7 +599,7 @@ Opts = [&transport_opt;]
<p>
A connecting transport is attempting to establish/reestablish a
-transport connection with a peer following &reconnect_timer; or
+transport connection with a peer following &connect_timer; or
&watchdog_timer; expiry.</p>
</item>
@@ -765,7 +765,7 @@ the application's &dictionary; file.</p>
The capabilities advertised by a node must match its configured
applications. In particular, <c>application</c> configuration must
be matched by corresponding &capability; configuration, of
-Application-Id AVP's in particular.</p>
+*-Application-Id AVPs in particular.</p>
</warning>
</item>
@@ -804,7 +804,7 @@ Defaults to <c>nodes</c>.</p>
<p>
Specifies a constant value <c>H</c> for the topmost <c>32-N</c> bits of
of 32-bit End-to-End and Hop-by-Hop identifiers generated
-by the service, either explicity or as a return value of a function
+by the service, either explicitly or as a return value of a function
to be evaluated at &start_service;.
In particular, an identifier <c>Id</c> is mapped to a new identifier
as follows.</p>
@@ -946,7 +946,7 @@ Applications not configured on the service in question are ignored.</p>
The capabilities advertised by a node must match its configured
applications.
In particular, setting <c>applications</c> on a transport typically
-implies having to set matching Application-Id AVP's in a
+implies having to set matching *-Application-Id AVPs in a
&capabilities; tuple.</p>
</warning>
@@ -956,7 +956,7 @@ implies having to set matching Application-Id AVP's in a
<tag><c>{capabilities, [&capability;]}</c></tag>
<item>
<p>
-AVP's used to construct outgoing CER/CEA messages.
+AVPs used to construct outgoing CER/CEA messages.
Values take precedence over any specified on the service in
question.</p>
@@ -1022,13 +1022,43 @@ The number of milliseconds after which a transport process having an
established transport connection will be terminated if the expected
capabilities exchange message (CER or CEA) is not received from the peer.
For a connecting transport, the timing of reconnection attempts is
-governed by &watchdog_timer; or &reconnect_timer; expiry.
+governed by &watchdog_timer; or &connect_timer; expiry.
For a listening transport, the peer determines the timing.</p>
<p>
Defaults to 10000.</p>
</item>
+<marker id="connect_timer"/>
+<tag><c>{connect_timer, Tc}</c></tag>
+<item>
+<pre>
+Tc = &dict_Unsigned32;
+</pre>
+
+<p>
+For a connecting transport, the &the_rfc; Tc timer, in milliseconds.
+Note that this timer determines the frequency with which a transport
+will attempt to establish an initial connection with its peer
+following transport configuration: once an initial connection has been
+established it's &watchdog_timer; that determines the frequency of
+reconnection attempts, as required by RFC 3539.</p>
+
+<p>
+For a listening transport, the timer specifies the time after which a
+previously connected peer will be forgotten: a connection after this time is
+regarded as an initial connection rather than a reestablishment,
+causing the RFC 3539 state machine to pass to state OKAY rather than
+REOPEN.
+Note that these semantics are not governed by the RFC and
+that a listening transport's &connect_timer; should be greater
+than its peer's Tw plus jitter.</p>
+
+<p>
+Defaults to 30000 for a connecting transport and 60000 for a listening
+transport.</p>
+</item>
+
<marker id="disconnect_cb"/>
<tag><c>{disconnect_cb, &evaluable;}</c></tag>
@@ -1145,36 +1175,6 @@ See &man_tcp; for the behaviour of that module.</p>
</note>
</item>
-<marker id="reconnect_timer"/>
-<tag><c>{reconnect_timer, Tc}</c></tag>
-<item>
-<pre>
-Tc = &dict_Unsigned32;
-</pre>
-
-<p>
-For a connecting transport, the &the_rfc; Tc timer, in milliseconds.
-Note that this timer determines the frequency with which a transport
-will attempt to establish a connection with its peer only <em>before</em>
-an initial connection is established: once there is an initial
-connection it's &watchdog_timer; that determines the
-frequency of reconnection attempts, as required by RFC 3539.</p>
-
-<p>
-For a listening transport, the timer specifies the time after which a
-previously connected peer will be forgotten: a connection after this time is
-regarded as an initial connection rather than a reestablishment,
-causing the RFC 3539 state machine to pass to state OKAY rather than
-REOPEN.
-Note that these semantics are not governed by the RFC and
-that a listening transport's &reconnect_timer; should be greater
-than its peer's Tw plus jitter.</p>
-
-<p>
-Defaults to 30000 for a connecting transport and 60000 for a listening
-transport.</p>
-</item>
-
<marker id="spawn_opt"/>
<tag><c>{spawn_opt, [term()]}</c></tag>
<item>
@@ -1661,7 +1661,7 @@ R_Flag}</c>.</p>
Note that <c>watchdog</c>, <c>peer</c>, <c>apps</c>, <c>caps</c>
and <c>port</c> entries depend on connectivity
with the peer and may not be present.
-Note also that the <c>statistics</c> entry presents values acuumulated
+Note also that the <c>statistics</c> entry presents values accumulated
during the lifetime of the transport configuration.</p>
<p>
diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml
index 90a36f8d53..67c430c40a 100644
--- a/lib/diameter/doc/src/diameter_app.xml
+++ b/lib/diameter/doc/src/diameter_app.xml
@@ -308,7 +308,7 @@ The return value <c>{Peer, NewState}</c> is only allowed if
the Diameter application in question was configured with the
&mod_application_opt; <c>{call_mutates_state, true}</c>.
Otherwise, the <c>State</c> argument is always
-the intial value as configured on the application, not any subsequent
+the initial value as configured on the application, not any subsequent
value returned by a &peer_up;
or &peer_down; callback.</p>
</warning>
@@ -565,7 +565,7 @@ Equivalent to</p>
</pre>
<p>
where <c>Avps</c> sets the Origin-Host, Origin-Realm, the specified
-Result-Code and (if the request contained one) Session-Id AVP's, and
+Result-Code and (if the request contained one) Session-Id AVPs, and
possibly Failed-AVP as described below.</p>
<p>
diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml
index f0e6de102f..308a56fab7 100644
--- a/lib/diameter/doc/src/diameter_codec.xml
+++ b/lib/diameter/doc/src/diameter_codec.xml
@@ -73,7 +73,7 @@ are defined in diameter.hrl, which can be included as follows.</p>
</pre>
<p>
-Application-specific records are definied in the hrl
+Application-specific records are defined in the hrl
files resulting from dictionary file compilation.</p>
</description>
@@ -122,7 +122,7 @@ Fields have the following types.</p>
<item>
<p>
Values in the AVP header, corresponding to AVP Code, the M flag, P
-flags and Vendor-ID respectivelty.
+flags and Vendor-ID respectively.
A Vendor-ID other than <c>undefined</c> implies a set V flag.</p>
</item>
@@ -222,7 +222,7 @@ header.</p>
<tag><c>is_retransmitted = boolean()</c></tag>
<item>
<p>
-Values correspoding to the R(equest), P(roxiable), E(rror)
+Values corresponding to the R(equest), P(roxiable), E(rror)
and T(Potentially re-transmitted message) flags of the Diameter
header.</p>
</item>
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index c7994ad774..810a146b88 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -431,7 +431,7 @@ equivalent to specifying it with <c>@avp_vendor_id</c>.</p>
Defines values of AVP Name having type Enumerated.
Section content consists of names and corresponding integer values.
Integer values can be prefixed with 0x to be interpreted as
-hexidecimal.</p>
+hexadecimal.</p>
<p>
Note that the AVP in question can be defined in an inherited
diff --git a/lib/diameter/doc/src/diameter_intro.xml b/lib/diameter/doc/src/diameter_intro.xml
index 7764cb6133..93293f2d8e 100644
--- a/lib/diameter/doc/src/diameter_intro.xml
+++ b/lib/diameter/doc/src/diameter_intro.xml
@@ -40,7 +40,7 @@ under the License.
The diameter application is an implementation of the Diameter protocol
as defined by &the_rfc;.
It supports arbitrary Diameter applications by way of a
-<em>dictionary</em> interface that allows messages and AVP's to be
+<em>dictionary</em> interface that allows messages and AVPs to be
defined and input into diameter as configuration.
It has support for all roles defined in the RFC: client, server and
agent.
@@ -69,7 +69,7 @@ interface</seealso>.</p>
<p>
While a service typically implements a single Diameter node (as
identified by an Origin-Host AVP), transports can themselves be
-associated with capabilities AVP's so that a single service can be
+associated with capabilities AVPs so that a single service can be
used to implement more than one Diameter node.</p>
<p>
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
index c9023fd8fb..e1673378df 100644
--- a/lib/diameter/doc/src/diameter_make.xml
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY compile_forms2
+ '<seealso marker="compiler:compile#forms-2">compile:forms/2</seealso>'>
<!ENTITY filename
'<seealso marker="kernel:file#type-name">file:name()</seealso>'>
<!ENTITY dictionary
@@ -51,7 +53,7 @@ under the License.
The function &codec; is used to compile a diameter
&dictionary; into Erlang source.
The resulting source implements the interface diameter required
-to encode and decode the dictionary's messages and AVP's.</p>
+to encode and decode the dictionary's messages and AVPs.</p>
<p>
The utility &man_compile; provides an alternate compilation
@@ -64,16 +66,47 @@ interface.</p>
<funcs>
<func>
-<name>codec(Path::string(), [Opt]) -> ok | {error, Reason}</name>
+<name>codec(File :: iolist() | binary(), [Opt]) -> ok
+ | {ok, [Out]}
+ | {error, Reason}</name>
<fsummary>Compile a dictionary file into Erlang source.</fsummary>
<desc>
<p>
-Compile a single dictionary file to Erlang source.
-<c>Opt</c> can have the following types.</p>
+Compile a single dictionary file.
+The input <c>File</c> can be either a path or a literal dictionary,
+the occurrence of newline (ascii NL) or carriage return (ascii CR)
+identifying the latter.
+<c>Opt</c> determines the format of the results and whether they are
+written to file or returned, and can have the following types.</p>
<taglist>
+<tag><c>parse | forms | erl | hrl</c></tag>
+<item>
+<p>
+Specifies an output format.
+Whether the output is returned or written to file depends on whether
+or not option <c>return</c> is specified.
+When written to file, the resulting file(s) will have extensions
+<c>.D</c>, <c>.F</c>, <c>.erl</c>, and <c>.hrl</c>
+respectively, basenames defaulting to <c>dictionary</c> if the input
+dictionary is literal and does not specify <c>&dict_name;</c>.
+When returned, results are in the order of the corresponding format
+options.
+Format options default to <c>erl</c> and <c>hrl</c> (in this order) if
+unspecified.</p>
+
+<p>
+The <c>parse</c> format is an internal representation that can be
+passed to &flatten; and &format;, while the <c>forms</c> format can be
+passed to &compile_forms2;.
+The <c>erl</c> and <c>hrl</c> formats are returned as
+iolists.</p>
+<!-- That codec/2 can take the parsed format is undocumented, and
+ options name and inherits have no effect in this case. -->
+</item>
+
<tag><c>{include, string()}</c></tag>
<item>
<p>
@@ -90,7 +123,15 @@ Multiple <c>include</c> options can be specified.</p>
<item>
<p>
Write generated source to the specified directory.
-Defaults to the current working directory.</p>
+Defaults to the current working directory.
+Has no effect if option <c>return</c> is specified.</p>
+</item>
+
+<tag><c>return</c></tag>
+<item>
+<p>
+Return results in a <c>{ok, [Out]}</c> tuple instead of writing to
+file and returning <c>ok</c>.</p>
</item>
<tag><c>{name|prefix, string()}</c></tag>
@@ -108,7 +149,7 @@ Transform the input dictionary before compilation, appending
<c>&dict_inherits;</c> of the specified string.</p>
<p>
-Two forms of <c>@inherits</c> have special meaning:</p>
+Two forms have special meaning:</p>
<pre>
{inherits, "-"}
@@ -127,6 +168,41 @@ Multiple <c>inherits</c> options can be specified.</p>
</taglist>
+<p>
+Note that a dictionary's <c>&dict_name;</c>, together with the
+<c>outdir</c> option, determine the output paths when the
+<c>return</c> option is not specified.
+The <c>&dict_name;</c> of a literal input dictionary defaults to
+<c>dictionary</c>.</p>
+
+</desc>
+</func>
+
+<!-- ===================================================================== -->
+
+<func>
+<name>format(Parsed) -> iolist()</name>
+<fsummary>Format a parsed dictionary.</fsummary>
+<desc>
+<p>
+Turns a parsed dictionary, as returned by &codec;, back into the
+dictionary format.</p>
+</desc>
+</func>
+
+<!-- ===================================================================== -->
+
+<func>
+<name>flatten(Parsed) -> term()</name>
+<fsummary>Flatten a parsed dictionary.</fsummary>
+<desc>
+
+<p>
+Reconstitute a parsed dictionary, as returned by &codec;, without
+using <c>&dict_inherits;</c>.
+That is, construct an equivalent dictionary in which all AVP's are
+definined in the dictionary itself.
+The return value is also a parsed dictionary.</p>
</desc>
</func>
@@ -138,11 +214,7 @@ Multiple <c>inherits</c> options can be specified.</p>
<title>BUGS</title>
<p>
-All options are string-valued.
-In particular, it is not currently possible to specify
-an &dict_inherits; module as an atom(), or a path as an arbitrary
-&filename;</p>
-
+Unrecognized options are silently ignored.</p>
</section>
<!-- ===================================================================== -->
diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml
index c0040f6198..fb7075f2cd 100644
--- a/lib/diameter/doc/src/diameter_sctp.xml
+++ b/lib/diameter/doc/src/diameter_sctp.xml
@@ -90,7 +90,7 @@ Options <c>raddr</c> and <c>rport</c> specify the remote address
and port for a connecting transport and not valid for a listening
transport: the former is required while latter defaults to 3868 if
unspecified.
-Mupltiple <c>raddr</c> options can be specified, in which case the
+Multiple <c>raddr</c> options can be specified, in which case the
connecting transport in question attempts each in sequence until
an association is established.</p>
diff --git a/lib/diameter/doc/src/diameter_soc_rfc6733.xml b/lib/diameter/doc/src/diameter_soc_rfc6733.xml
index d7f69c4818..34ec902632 100644
--- a/lib/diameter/doc/src/diameter_soc_rfc6733.xml
+++ b/lib/diameter/doc/src/diameter_soc_rfc6733.xml
@@ -1272,7 +1272,7 @@ during capabilities exchange.)</p>
<p>
The frequency of reconnection attempts is configured with the
-&mod_transport_opt; <c>reconnect_timer</c> and
+&mod_transport_opt; <c>connect_timer</c> and
<c>watchdog_timer</c>.</p>
<pre>
diff --git a/lib/diameter/doc/src/diameter_compile.xml b/lib/diameter/doc/src/diameterc.xml
index 512070dfd0..5bffe9a771 100644
--- a/lib/diameter/doc/src/diameter_compile.xml
+++ b/lib/diameter/doc/src/diameterc.xml
@@ -29,7 +29,7 @@ supplied.
<docno></docno>
<date></date>
<rev></rev>
-<file>diameter_compile.xml</file>
+<file>diameterc.xml</file>
</header>
<com>diameterc</com>
@@ -41,7 +41,7 @@ supplied.
The diameterc utility is used to compile a diameter
&dictionary; into Erlang source.
The resulting source implements the interface diameter required
-to encode and decode the dictionary's messages and AVP's.</p>
+to encode and decode the dictionary's messages and AVPs.</p>
<p>
The module &man_make; provides an alternate compilation interface.</p>
@@ -83,7 +83,7 @@ Defaults to the current working directory.</p>
<tag><![CDATA[-H]]></tag>
<item>
<p>
-Supress erl and hrl generation, respectively.</p>
+Suppress erl and hrl generation, respectively.</p>
</item>
<tag><![CDATA[--name <name>]]></tag>
diff --git a/lib/diameter/doc/src/files.mk b/lib/diameter/doc/src/files.mk
index 510786a7fb..6e8b1f9068 100644
--- a/lib/diameter/doc/src/files.mk
+++ b/lib/diameter/doc/src/files.mk
@@ -21,7 +21,7 @@ XML_APPLICATION_FILES = \
ref_man.xml
XML_REF1_FILES = \
- diameter_compile.xml
+ diameterc.xml
XML_REF3_FILES = \
diameter.xml \
diff --git a/lib/diameter/doc/src/ref_man.xml b/lib/diameter/doc/src/ref_man.xml
index 89d243cd8e..62ba02b0b5 100644
--- a/lib/diameter/doc/src/ref_man.xml
+++ b/lib/diameter/doc/src/ref_man.xml
@@ -39,7 +39,7 @@ applications on top of the Diameter protocol. </p>
</description>
<xi:include href="diameter.xml"/>
-<xi:include href="diameter_compile.xml"/>
+<xi:include href="diameterc.xml"/>
<xi:include href="diameter_app.xml"/>
<xi:include href="diameter_codec.xml"/>
<xi:include href="diameter_dict.xml"/>
diff --git a/lib/diameter/doc/src/seealso.ent b/lib/diameter/doc/src/seealso.ent
index 76b9823f79..7bf7460351 100644
--- a/lib/diameter/doc/src/seealso.ent
+++ b/lib/diameter/doc/src/seealso.ent
@@ -66,7 +66,7 @@ significant.
<!ENTITY disconnect_cb '<seealso marker="#disconnect_cb">disconnect_cb</seealso>'>
<!ENTITY transport_config '<seealso marker="#transport_config">transport_config</seealso>'>
<!ENTITY transport_module '<seealso marker="#transport_module">transport_module</seealso>'>
-<!ENTITY reconnect_timer '<seealso marker="#reconnect_timer">reconnect_timer</seealso>'>
+<!ENTITY connect_timer '<seealso marker="#connect_timer">connect_timer</seealso>'>
<!ENTITY watchdog_timer '<seealso marker="#watchdog_timer">watchdog_timer</seealso>'>
<!-- diameter_app -->
@@ -115,6 +115,8 @@ significant.
<!-- diameter_make -->
<!ENTITY make_codec '<seealso marker="diameter_make#codec-2">diameter_make:codec/2</seealso>'>
+<!ENTITY make_format '<seealso marker="diameter_make#format-1">diameter_make:format/1</seealso>'>
+<!ENTITY make_flatten '<seealso marker="diameter_make#flatten-1">diameter_make:flatten/1</seealso>'>
<!-- diameter_transport -->
diff --git a/lib/diameter/doc/standard/rfc7068.txt b/lib/diameter/doc/standard/rfc7068.txt
new file mode 100644
index 0000000000..70fc24fab0
--- /dev/null
+++ b/lib/diameter/doc/standard/rfc7068.txt
@@ -0,0 +1,1627 @@
+
+
+
+
+
+
+Internet Engineering Task Force (IETF) E. McMurry
+Request for Comments: 7068 B. Campbell
+Category: Informational Oracle
+ISSN: 2070-1721 November 2013
+
+
+ Diameter Overload Control Requirements
+
+Abstract
+
+ When a Diameter server or agent becomes overloaded, it needs to be
+ able to gracefully reduce its load, typically by advising clients to
+ reduce traffic for some period of time. Otherwise, it must continue
+ to expend resources parsing and responding to Diameter messages,
+ possibly resulting in a progressively severe overload condition. The
+ existing Diameter mechanisms are not sufficient for managing overload
+ conditions. This document describes the limitations of the existing
+ mechanisms. Requirements for new overload management mechanisms are
+ also provided.
+
+Status of This Memo
+
+ This document is not an Internet Standards Track specification; it is
+ published for informational purposes.
+
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Not all documents
+ approved by the IESG are a candidate for any level of Internet
+ Standard; see Section 2 of RFC 5741.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ http://www.rfc-editor.org/info/rfc7068.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 1]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+Copyright Notice
+
+ Copyright (c) 2013 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 2]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+Table of Contents
+
+ 1. Introduction ....................................................4
+ 1.1. Documentation Conventions ..................................4
+ 1.2. Causes of Overload .........................................5
+ 1.3. Effects of Overload ........................................6
+ 1.4. Overload vs. Network Congestion ............................6
+ 1.5. Diameter Applications in a Broader Network .................7
+ 2. Overload Control Scenarios ......................................7
+ 2.1. Peer-to-Peer Scenarios .....................................8
+ 2.2. Agent Scenarios ...........................................10
+ 2.3. Interconnect Scenario .....................................14
+ 3. Diameter Overload Case Studies .................................15
+ 3.1. Overload in Mobile Data Networks ..........................15
+ 3.2. 3GPP Study on Core Network Overload .......................16
+ 4. Existing Mechanisms ............................................17
+ 5. Issues with the Current Mechanisms .............................18
+ 5.1. Problems with Implicit Mechanism ..........................18
+ 5.2. Problems with Explicit Mechanisms .........................18
+ 6. Extensibility and Application Independence .....................19
+ 7. Solution Requirements ..........................................20
+ 7.1. General ...................................................20
+ 7.2. Performance ...............................................21
+ 7.3. Heterogeneous Support for Solution ........................22
+ 7.4. Granular Control ..........................................23
+ 7.5. Priority and Policy .......................................23
+ 7.6. Security ..................................................23
+ 7.7. Flexibility and Extensibility .............................24
+ 8. Security Considerations ........................................25
+ 8.1. Access Control ............................................25
+ 8.2. Denial-of-Service Attacks .................................26
+ 8.3. Replay Attacks ............................................26
+ 8.4. Man-in-the-Middle Attacks .................................26
+ 8.5. Compromised Hosts .........................................27
+ 9. References .....................................................27
+ 9.1. Normative References ......................................27
+ 9.2. Informative References ....................................27
+ Appendix A. Contributors ..........................................29
+ Appendix B. Acknowledgements ......................................29
+
+
+
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 3]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+1. Introduction
+
+ A Diameter [RFC6733] node is said to be overloaded when it has
+ insufficient resources to successfully process all of the Diameter
+ requests that it receives. When a node becomes overloaded, it needs
+ to be able to gracefully reduce its load, typically by advising
+ clients to reduce traffic for some period of time. Otherwise, it
+ must continue to expend resources parsing and responding to Diameter
+ messages, possibly resulting in a progressively severe overload
+ condition. The existing mechanisms provided by Diameter are not
+ sufficient for managing overload conditions. This document describes
+ the limitations of the existing mechanisms and provides requirements
+ for new overload management mechanisms.
+
+ This document draws on the work done on SIP overload control
+ ([RFC5390], [RFC6357]) as well as on experience gained via overload
+ handling in Signaling System No. 7 (SS7) networks and studies done by
+ the Third Generation Partnership Project (3GPP) (Section 3).
+
+ Diameter is not typically an end-user protocol; rather, it is
+ generally used as one component in support of some end-user activity.
+
+ For example, a SIP server might use Diameter to authenticate and
+ authorize user access. Overload in the Diameter backend
+ infrastructure will likely impact the experience observed by the end
+ user in the SIP application.
+
+ The impact of Diameter overload on the client application (a client
+ application may use the Diameter protocol and other protocols to do
+ its job) is beyond the scope of this document.
+
+ This document presents non-normative descriptions of causes of
+ overload, along with related scenarios and studies. Finally, it
+ offers a set of normative requirements for an improved overload
+ indication mechanism.
+
+1.1. Documentation Conventions
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as defined in [RFC2119], with the
+ exception that they are not intended for interoperability of
+ implementations. Rather, they are used to describe requirements
+ towards future specifications where the interoperability requirements
+ will be defined.
+
+ The terms "client", "server", "agent", "node", "peer", "upstream",
+ and "downstream" are used as defined in [RFC6733].
+
+
+
+McMurry & Campbell Informational [Page 4]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+1.2. Causes of Overload
+
+ Overload occurs when an element, such as a Diameter server or agent,
+ has insufficient resources to successfully process all of the traffic
+ it is receiving. Resources include all of the capabilities of the
+ element used to process a request, including CPU processing, memory,
+ I/O, and disk resources. It can also include external resources such
+ as a database or DNS server, in which case the CPU, processing,
+ memory, I/O, and disk resources of those elements are effectively
+ part of the logical element processing the request.
+
+ External resources can include upstream Diameter nodes; for example,
+ a Diameter agent can become effectively overloaded if one or more
+ upstream nodes are overloaded.
+
+ A Diameter node can become overloaded due to request levels that
+ exceed its capacity, a reduction of available resources (for example,
+ a local or upstream hardware failure), or a combination of the two.
+
+ Overload can occur for many reasons, including:
+
+ Inadequate capacity: When designing Diameter networks, that is,
+ application-layer multi-node Diameter deployments, it can be very
+ difficult to predict all scenarios that may cause elevated
+ traffic. It may also be more costly to implement support for some
+ scenarios than a network operator may deem worthwhile. This
+ results in the likelihood that a Diameter network will not have
+ adequate capacity to handle all situations.
+
+ Dependency failures: A Diameter node can become overloaded because a
+ resource on which it depends has failed or become overloaded,
+ greatly reducing the logical capacity of the node. In these
+ cases, even minimal traffic might cause the node to go into
+ overload. Examples of such dependency overloads include DNS
+ servers, databases, disks, and network interfaces that have failed
+ or become overloaded.
+
+ Component failures: A Diameter node can become overloaded when it is
+ a member of a cluster of servers that each share the load of
+ traffic and one or more of the other members in the cluster fail.
+ In this case, the remaining nodes take over the work of the failed
+ nodes. Normally, capacity planning takes such failures into
+ account, and servers are typically run with enough spare capacity
+ to handle failure of another node. However, unusual failure
+ conditions can cause many nodes to fail at once. This is often
+ the case with software failures, where a bad packet or bad
+ database entry hits the same bug in a set of nodes in a cluster.
+
+
+
+
+McMurry & Campbell Informational [Page 5]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ Network-initiated traffic flood: Certain access network events can
+ precipitate floods of Diameter signaling traffic. For example,
+ operational changes can trigger avalanche restarts, or frequent
+ radio overlay handovers can generate excessive authorization
+ requests. Failure of a Diameter proxy may also result in a large
+ amount of signaling as connections and sessions are reestablished.
+
+ Subscriber-initiated traffic flood: Large gatherings of subscribers
+ or events that result in many subscribers interacting with the
+ network in close time proximity can result in Diameter signaling
+ traffic floods. For example, the finale of a large fireworks show
+ could be immediately followed by many subscribers posting
+ messages, pictures, and videos concentrated on one portion of a
+ network. Subscriber devices such as smartphones may use
+ aggressive registration strategies that generate unusually high
+ Diameter traffic loads.
+
+ DoS attacks: An attacker wishing to disrupt service in the network
+ can cause a large amount of traffic to be launched at a target
+ element. This can be done from a central source of traffic or
+ through a distributed DoS attack. In all cases, the volume of
+ traffic well exceeds the capacity of the element, sending the
+ system into overload.
+
+1.3. Effects of Overload
+
+ Modern Diameter networks, composed of application-layer multi-node
+ deployments of Diameter elements, may operate at very large
+ transaction volumes. If a Diameter node becomes overloaded or, even
+ worse, fails completely, a large number of messages may be lost very
+ quickly. Even with redundant servers, many messages can be lost in
+ the time it takes for failover to complete. While a Diameter client
+ or agent should be able to retry such requests, an overloaded peer
+ may cause a sudden large increase in the number of transactions
+ needing to be retried, rapidly filling local queues or otherwise
+ contributing to local overload. Therefore, Diameter devices need to
+ be able to shed load before critical failures can occur.
+
+1.4. Overload vs. Network Congestion
+
+ This document uses the term "overload" to refer to application-layer
+ overload at Diameter nodes. This is distinct from "network
+ congestion", that is, congestion that occurs at the lower networking
+ layers that may impact the delivery of Diameter messages between
+ nodes. This document recognizes that element overload and network
+ congestion are interrelated, and that overload can contribute to
+ network congestion and vice versa.
+
+
+
+
+McMurry & Campbell Informational [Page 6]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ Network congestion issues are better handled by the transport
+ protocols. Diameter uses TCP and the Stream Control Transmission
+ Protocol (SCTP), both of which include congestion management
+ features. Analysis of whether those features are sufficient for
+ transport-level congestion between Diameter nodes and of any work to
+ further mitigate network congestion is out of scope for both this
+ document and the work proposed by it.
+
+1.5. Diameter Applications in a Broader Network
+
+ Most elements using Diameter applications do not use Diameter
+ exclusively. It is important to realize that overload of an element
+ can be caused by a number of factors that may be unrelated to the
+ processing of Diameter or Diameter applications.
+
+ An element that doesn't use Diameter exclusively needs to be able to
+ signal to Diameter peers that it is experiencing overload regardless
+ of the cause of the overload, since the overload will affect that
+ element's ability to process Diameter transactions. If the element
+ communicates with protocols other than Diameter, it may also need to
+ signal the overload situation on these protocols, depending on its
+ function and the architecture of the network and application for
+ which it is providing services. Whether that is necessary can only
+ be decided within the context of that architecture and use cases.
+ This specification details the requirements for a mechanism for
+ signaling overload with Diameter; this mechanism provides Diameter
+ nodes the ability to inform their Diameter peers of overload,
+ mitigating that part of the issue. Diameter nodes may need to use
+ this, as well as other mechanisms, to solve their broader overload
+ issues. Indicating overload on protocols other than Diameter is out
+ of scope for this document and for the work proposed by it.
+
+2. Overload Control Scenarios
+
+ Several Diameter deployment scenarios exist that may impact overload
+ management. The following scenarios help motivate the requirements
+ for an overload management mechanism.
+
+ These scenarios are by no means exhaustive and are in general
+ simplified for the sake of clarity. In particular, this document
+ assumes for the sake of clarity that the client sends Diameter
+ requests to the server, and the server sends responses to the client,
+ even though Diameter supports bidirectional applications. Each
+ direction in such an application can be modeled separately.
+
+ In a large-scale deployment, many of the nodes represented in these
+ scenarios would be deployed as clusters of servers. This document
+ assumes that such a cluster is responsible for managing its own
+
+
+
+McMurry & Campbell Informational [Page 7]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ internal load-balancing and overload management so that it appears as
+ a single Diameter node. That is, other Diameter nodes can treat it
+ as a single, monolithic node for the purposes of overload management.
+
+ These scenarios do not illustrate the client application. As
+ mentioned in Section 1, Diameter is not typically an end-user
+ protocol; rather, it is generally used in support of some other
+ client application. These scenarios do not consider the impact of
+ Diameter overload on the client application.
+
+2.1. Peer-to-Peer Scenarios
+
+ This section describes Diameter peer-to-peer scenarios, that is,
+ scenarios where a Diameter client talks directly with a Diameter
+ server, without the use of a Diameter agent.
+
+ Figure 1 illustrates the simplest possible Diameter relationship.
+ The client and server share a one-to-one peer-to-peer relationship.
+ If the server becomes overloaded, either because the client exceeds
+ the server's capacity or because the server's capacity is reduced due
+ to some resource dependency, the client needs to reduce the amount of
+ Diameter traffic it sends to the server. Since the client cannot
+ forward requests to another server, it must either queue requests
+ until the server recovers or itself become overloaded in the context
+ of the client application and other protocols it may also use.
+
+ +------------------+
+ | |
+ | |
+ | Server |
+ | |
+ +--------+---------+
+ |
+ |
+ +--------+---------+
+ | |
+ | |
+ | Client |
+ | |
+ +------------------+
+
+ Figure 1: Basic Peer-to-Peer Scenario
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 8]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ Figure 2 shows a similar scenario, except in this case the client has
+ multiple servers that can handle work for a specific realm and
+ application. If Server 1 becomes overloaded, the client can forward
+ traffic to Server 2. Assuming that Server 2 has sufficient reserve
+ capacity to handle the forwarded traffic, the client should be able
+ to continue serving client application protocol users. If Server 1
+ is approaching overload, but can still handle some number of new
+ requests, it needs to be able to instruct the client to forward a
+ subset of its traffic to Server 2.
+
+ +------------------+ +------------------+
+ | | | |
+ | | | |
+ | Server 1 | | Server 2 |
+ | | | |
+ +--------+-`.------+ +------.'+---------+
+ `. .'
+ `. .'
+ `. .'
+ `. .'
+ +-------`.'--------+
+ | |
+ | |
+ | Client |
+ | |
+ +------------------+
+
+ Figure 2: Multiple-Server Peer-to-Peer Scenario
+
+ Figure 3 illustrates a peer-to-peer scenario with multiple Diameter
+ realm and application combinations. In this example, Server 2 can
+ handle work for both applications. Each application might have
+ different resource dependencies. For example, a server might need to
+ access one database for Application A and another for Application B.
+ This creates a possibility that Server 2 could become overloaded for
+ Application A but not for Application B, in which case the client
+ would need to divert some part of its Application A requests to
+ Server 1, but the client should not divert any Application B
+ requests. This requires that Server 2 be able to distinguish between
+ applications when it indicates an overload condition to the client.
+
+ On the other hand, it's possible that the servers host many
+ applications. If Server 2 becomes overloaded for all applications,
+ it would be undesirable for it to have to notify the client
+ separately for each application. Therefore, it also needs a way to
+ indicate that it is overloaded for all possible applications.
+
+
+
+
+
+McMurry & Campbell Informational [Page 9]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ +---------------------------------------------+
+ | Application A +----------------------+----------------------+
+ |+------------------+ | +----------------+ | +------------------+|
+ || | | | | | | ||
+ || | | | | | | ||
+ || Server 1 | | | Server 2 | | | Server 3 ||
+ || | | | | | | ||
+ |+--------+---------+ | +-------+--------+ | +-+----------------+|
+ | | | | | | |
+ +---------+-----------+----------+-----------+ | |
+ | | | | |
+ | | | | Application B |
+ | +----------+----------------+-----------------+
+ ``-.._ | |
+ `-..__ | _.-''
+ `--._ | _.-''
+ ``-._ | _.-''
+ +-----`-.-''-----+
+ | |
+ | |
+ | Client |
+ | |
+ +----------------+
+
+ Figure 3: Multiple-Application Peer-to-Peer Scenario
+
+2.2. Agent Scenarios
+
+ This section describes scenarios that include a Diameter agent, in
+ the form of either a Diameter relay or Diameter proxy. These
+ scenarios do not consider Diameter redirect agents, since they are
+ more readily modeled as end servers. The examples have been kept
+ simple deliberately, to illustrate basic concepts. Significantly
+ more complicated topologies are possible with Diameter, including
+ multiple intermediate agents in a path connected in a variety
+ of ways.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 10]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ Figure 4 illustrates a simple Diameter agent scenario with a single
+ client, agent, and server. In this case, overload can occur at the
+ server, at the agent, or both. But in most cases, client behavior is
+ the same whether overload occurs at the server or at the agent. From
+ the client's perspective, server overload and agent overload are the
+ same thing.
+
+ +------------------+
+ | |
+ | |
+ | Server |
+ | |
+ +--------+---------+
+ |
+ |
+ +--------+---------+
+ | |
+ | |
+ | Agent |
+ | |
+ +--------+---------+
+ |
+ |
+ +--------+---------+
+ | |
+ | |
+ | Client |
+ | |
+ +------------------+
+
+ Figure 4: Basic Agent Scenario
+
+ Figure 5 shows an agent scenario with multiple servers. If Server 1
+ becomes overloaded but Server 2 has sufficient reserve capacity, the
+ agent may be able to transparently divert some or all Diameter
+ requests originally bound for Server 1 to Server 2.
+
+ In most cases, the client does not have detailed knowledge of the
+ Diameter topology upstream of the agent. If the agent uses dynamic
+ discovery to find eligible servers, the set of eligible servers may
+ not be enumerable from the perspective of the client. Therefore, in
+ most cases the agent needs to deal with any upstream overload issues
+ in a way that is transparent to the client. If one server notifies
+ the agent that it has become overloaded, the notification should not
+ be passed back to the client in a way that the client could
+ mistakenly perceive the agent itself as being overloaded. If the set
+
+
+
+
+
+McMurry & Campbell Informational [Page 11]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ of all possible destinations upstream of the agent no longer has
+ sufficient capacity for incoming load, the agent itself becomes
+ effectively overloaded.
+
+ On the other hand, there are cases where the client needs to be able
+ to select a particular server from behind an agent. For example, if
+ a Diameter request is part of a multiple-round-trip authentication,
+ or is otherwise part of a Diameter "session", it may have a
+ Destination-Host Attribute-Value Pair (AVP) that requires that the
+ request be served by Server 1. Therefore, the agent may need to
+ inform a client that a particular upstream server is overloaded or
+ otherwise unavailable. Note that there can be many ways a server can
+ be specified, which may have different implications (e.g., by IP
+ address, by host name, etc).
+
+ +------------------+ +------------------+
+ | | | |
+ | | | |
+ | Server 1 | | Server 2 |
+ | | | |
+ +--------+-`.------+ +------.'+---------+
+ `. .'
+ `. .'
+ `. .'
+ `. .'
+ +-------`.'--------+
+ | |
+ | |
+ | Agent |
+ | |
+ +--------+---------+
+ |
+ |
+ |
+ +--------+---------+
+ | |
+ | |
+ | Client |
+ | |
+ +------------------+
+
+ Figure 5: Multiple-Server Agent Scenario
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 12]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ Figure 6 shows a scenario where an agent routes requests to a set of
+ servers for more than one Diameter realm and application. In this
+ scenario, if Server 1 becomes overloaded or unavailable while
+ Server 2 still has available capacity, the agent may effectively
+ operate at reduced capacity for Application A but at full capacity
+ for Application B. Therefore, the agent needs to be able to report
+ that it is overloaded for one application but not for another.
+
+ +--------------------------------------------+
+ | Application A +----------------------+----------------------+
+ |+------------------+ | +----------------+ | +------------------+|
+ || | | | | | | ||
+ || | | | | | | ||
+ || Server 1 | | | Server 2 | | | Server 3 ||
+ || | | | | | | ||
+ |+---------+--------+ | +-------+--------+ | +--+---------------+|
+ | | | | | | |
+ +----------+----------+----------+-----------+ | |
+ | | | | |
+ | | | | Application B |
+ | +----------+-----------------+----------------+
+ | | |
+ ``--.__ | _.
+ ``-.__ | __.--''
+ `--.._ | _..--'
+ +----``-+.''-----+
+ | |
+ | |
+ | Agent |
+ | |
+ +-------+--------+
+ |
+ |
+ +-------+--------+
+ | |
+ | |
+ | Client |
+ | |
+ +----------------+
+
+ Figure 6: Multiple-Application Agent Scenario
+
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 13]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+2.3. Interconnect Scenario
+
+ Another scenario to consider when looking at Diameter overload is
+ that of multiple network operators using Diameter components
+ connected through an interconnect service, e.g., using IPX (IP Packet
+ eXchange). IPX [IR.34] is an Inter-Operator IP Backbone that
+ provides a roaming interconnection network between mobile operators
+ and service providers. IPX is also used to transport Diameter
+ signaling between operators [IR.88]. Figure 7 shows two network
+ operators with an interconnect network between them. There could be
+ any number of these networks between any two network operators'
+ networks.
+
+ +-------------------------------------------+
+ | Interconnect |
+ | |
+ | +--------------+ +--------------+ |
+ | | Server 3 |------| Server 4 | |
+ | +--------------+ +--------------+ |
+ | .' `. |
+ +------.-'--------------------------`.------+
+ .' `.
+ .-' `.
+ ------------.'-----+ +----`.-------------
+ +----------+ | | +----------+
+ | Server 1 | | | | Server 2 |
+ +----------+ | | +----------+
+ | |
+ Network Operator 1 | | Network Operator 2
+ -------------------+ +-------------------
+
+ Figure 7: Two-Network Interconnect Scenario
+
+ The characteristics of the information that an operator would want to
+ share over such a connection are different from the information
+ shared between components within a network operator's network. For
+ example, network operators may not want to convey topology or
+ operational information; this would in turn limit how much overload
+ and loading information can be sent. For the interconnect scenario
+ shown in Figure 7, Server 2 may want to signal overload to Server 1,
+ to affect traffic coming from Network Operator 1.
+
+ This case is distinct from those internal to a network operator's
+ network, where there may be many more elements in a more complicated
+ topology. Also, the elements in the interconnect network may not
+ support Diameter overload control, and the network operators may not
+ want the interconnect network to use overload or loading information.
+ They may only want the information to pass through the interconnect
+
+
+
+McMurry & Campbell Informational [Page 14]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ network without further processing or action by the interconnect
+ network, even if the elements in the interconnect network do support
+ Diameter overload control.
+
+3. Diameter Overload Case Studies
+
+3.1. Overload in Mobile Data Networks
+
+ As the number of smartphone devices that are Third Generation (3G)
+ and Long Term Evolution (LTE) enabled continues to expand in mobile
+ networks, there have been situations where high signaling traffic
+ load led to overload events at the Diameter-based Home Location
+ Registers (HLRs) and/or Home Subscriber Servers (HSS) [TR23.843].
+ The root causes of the HLR overload events were manifold but included
+ hardware failure and procedural errors. The result was high
+ signaling traffic load on the HLR and HSS.
+
+ The 3GPP architecture [TS23.002] makes extensive use of Diameter. It
+ is used for mobility management [TS29.272], the IP Multimedia
+ Subsystem (IMS) [TS29.228], and policy and charging control
+ [TS29.212], as well as other functions. The details of the
+ architecture are out of scope for this document, but it is worth
+ noting that there are quite a few Diameter applications, some with
+ quite large amounts of Diameter signaling in deployed networks.
+
+ The 3GPP specifications do not currently address overload for
+ Diameter applications or provide a load control mechanism equivalent
+ to those provided in the more traditional SS7 elements in the Global
+ System for Mobile Communications (GSM); see [TS29.002]. The
+ capabilities specified in the 3GPP standards do not adequately
+ address the abnormal condition where excessively high signaling
+ traffic load situations are experienced.
+
+ Smartphones, which comprise an increasingly large percentage of
+ mobile devices, contribute much more heavily, relative to
+ non-smartphones, to the continuation of a registration surge, due to
+ their very aggressive registration algorithms. Smartphone behavior
+ contributes to network loading and can contribute to overload
+ conditions. The aggressive smartphone logic is designed to:
+
+ a. always have voice and data registration, and
+
+ b. constantly try to be on 3G or LTE data (and thus on 3G voice or
+ Voice over LTE (VoLTE) [IR.92]) for their added benefits.
+
+ Non-smartphones typically have logic to wait for a time period after
+ registering successfully on voice and data.
+
+
+
+
+McMurry & Campbell Informational [Page 15]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ The aggressive smartphone registration is problematic in two ways:
+
+ o first, by generating excessive signaling load towards the HSS that
+ is ten times the load from a non-smartphone, and
+
+ o second, by causing continual registration attempts when a network
+ failure affects registrations through the 3G data network.
+
+3.2. 3GPP Study on Core Network Overload
+
+ A study in the 3GPP System Aspects working group 2 (SA2) on core
+ network overload has produced the technical report [TR23.843]. This
+ enumerates several causes of overload in mobile core networks,
+ including portions that are signaled using Diameter. [TR23.843] is a
+ work in progress and is not complete. However, it is useful for
+ pointing out scenarios and the general need for an overload control
+ mechanism for Diameter.
+
+ It is common for mobile networks to employ more than one radio
+ technology and to do so in an overlay fashion with multiple
+ technologies present in the same location (such as 2nd or 3rd
+ generation mobile technologies, along with LTE). This presents
+ opportunities for traffic storms when issues occur on one overlay and
+ not another as all devices that had been on the overlay with issues
+ switch. This causes a large amount of Diameter traffic as locations
+ and policies are updated.
+
+ Another scenario called out by this study is a flood of registration
+ and mobility management events caused by some element in the core
+ network failing. This flood of traffic from end nodes falls under
+ the network-initiated traffic flood category. There is likely to
+ also be traffic resulting directly from the component failure in this
+ case. A similar flood can occur when elements or components recover
+ as well.
+
+ Subscriber-initiated traffic floods are also indicated in this study
+ as an overload mechanism where a large number of mobile devices are
+ attempting to access services at the same time, such as in response
+ to an entertainment event or a catastrophic event.
+
+ While this 3GPP study is concerned with the broader effects of these
+ scenarios on wireless networks and their elements, they have
+ implications specifically for Diameter signaling. One of the goals
+ of this document is to provide guidance for a core mechanism that can
+ be used to mitigate the scenarios called out by this study.
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 16]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+4. Existing Mechanisms
+
+ Diameter offers both implicit and explicit mechanisms for a Diameter
+ node to learn that a peer is overloaded or unreachable. The implicit
+ mechanism is simply the lack of responses to requests. If a client
+ fails to receive a response in a certain time period, it assumes that
+ the upstream peer is unavailable or is overloaded to the point of
+ effective unavailability. The watchdog mechanism [RFC3539] ensures
+ that transaction responses occur at a certain rate even when there is
+ otherwise little or no other Diameter traffic.
+
+ The explicit mechanism can involve specific protocol error responses,
+ where an agent or server tells a downstream peer that it is either
+ too busy to handle a request (DIAMETER_TOO_BUSY) or unable to route a
+ request to an upstream destination (DIAMETER_UNABLE_TO_DELIVER)
+ perhaps because that destination itself is overloaded to the point of
+ unavailability.
+
+ Another explicit mechanism, a DPR (Disconnect-Peer-Request) message,
+ can be sent with a Disconnect-Cause of BUSY. This signals the
+ sender's intent to close the transport connection and requests that
+ the client not reconnect.
+
+ Once a Diameter node learns via one of these mechanisms that an
+ upstream peer has become overloaded, it can then attempt to take
+ action to reduce the load. This usually means forwarding traffic to
+ an alternate destination, if available. If no alternate destination
+ is available, the node must either reduce the number of messages it
+ originates (in the case of a client) or inform the client to reduce
+ traffic (in the case of an agent).
+
+ Diameter requires the use of a congestion-managed transport layer,
+ currently TCP or SCTP, to mitigate network congestion. It is
+ expected that these transports manage network congestion and that
+ issues with transport (e.g., congestion propagation and window
+ management) are managed at that level. But even with a congestion-
+ managed transport, a Diameter node can become overloaded at the
+ Diameter protocol or application layers due to the causes described
+ in Section 1.2, and congestion-managed transports do not provide
+ facilities (and are at the wrong level) to handle server overload.
+ Transport-level congestion management is also not sufficient to
+ address overload in cases of multi-hop and multi-destination
+ signaling.
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 17]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+5. Issues with the Current Mechanisms
+
+ The currently available Diameter mechanisms for indicating an
+ overload condition are not adequate to avoid service outages due to
+ overload. This inadequacy may, in turn, contribute to broader
+ impacts resulting from overload due to unresponsive Diameter nodes
+ causing application-layer or transport-layer retransmissions. In
+ particular, they do not allow a Diameter agent or server to shed load
+ as it approaches overload. At best, a node can only indicate that it
+ needs to entirely stop receiving requests, i.e., that it has
+ effectively failed. Even that is problematic due to the inability to
+ indicate durational validity on the transient errors available in the
+ base Diameter protocol. Diameter offers no mechanism to allow a node
+ to indicate different overload states for different categories of
+ messages, for example, if it is overloaded for one Diameter
+ application but not another.
+
+5.1. Problems with Implicit Mechanism
+
+ The implicit mechanism doesn't allow an agent or server to inform the
+ client of a problem until it is effectively too late to do anything
+ about it. The client does not know that it needs to take action
+ until the upstream node has effectively failed. A Diameter node has
+ no opportunity to shed load early to avoid collapse in the first
+ place.
+
+ Additionally, the implicit mechanism cannot distinguish between
+ overload of a Diameter node and network congestion. Diameter treats
+ the failure to receive an answer as a transport failure.
+
+5.2. Problems with Explicit Mechanisms
+
+ The Diameter specification is ambiguous on how a client should handle
+ receipt of a DIAMETER_TOO_BUSY response. The base specification
+ [RFC6733] indicates that the sending client should attempt to send
+ the request to a different peer. It makes no suggestion that the
+ receipt of a DIAMETER_TOO_BUSY response should affect future Diameter
+ messages in any way.
+
+ The Authentication, Authorization, and Accounting (AAA) Transport
+ Profile [RFC3539] recommends that a AAA node that receives a "Busy"
+ response failover all remaining requests to a different agent or
+ server. But while the Diameter base specification explicitly depends
+ on [RFC3539] to define transport behavior, it does not refer to
+ [RFC3539] in the description of behavior on receipt of a
+ DIAMETER_TOO_BUSY error. There's a strong likelihood that at least
+ some implementations will continue to send Diameter requests to an
+ upstream peer even after receiving a DIAMETER_TOO_BUSY error.
+
+
+
+McMurry & Campbell Informational [Page 18]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ BCP 41 [RFC2914] describes, among other things, how end-to-end
+ application behavior can help avoid congestion collapse. In
+ particular, an application should avoid sending messages that will
+ never be delivered or processed. The DIAMETER_TOO_BUSY behavior as
+ described in the Diameter base specification fails at this, since if
+ an upstream node becomes overloaded, a client attempts each request
+ and does not discover the need to failover the request until the
+ initial attempt fails.
+
+ The situation is improved if implementations follow the [RFC3539]
+ recommendation to keep state about upstream peer overload. But even
+ then, the Diameter specification offers no guidance on how long a
+ client should wait before retrying the overloaded destination. If an
+ agent or server supports multiple realms and/or applications,
+ DIAMETER_TOO_BUSY offers no way to indicate that it is overloaded for
+ one application but not another. A DIAMETER_TOO_BUSY error can only
+ indicate overload at a "whole server" scope.
+
+ Agent processing of a DIAMETER_TOO_BUSY response is also problematic
+ as described in the base specification. DIAMETER_TOO_BUSY is defined
+ as a protocol error. If an agent receives a protocol error, it may
+ either handle it locally or forward the response back towards the
+ downstream peer. If a downstream peer receives the DIAMETER_TOO_BUSY
+ response, it may stop sending all requests to the agent for some
+ period of time, even though the agent may still be able to deliver
+ requests to other upstream peers.
+
+ DIAMETER_UNABLE_TO_DELIVER errors, or using DPR with cause code BUSY,
+ also have no mechanisms for specifying the scope or cause of the
+ failure, or the durational validity.
+
+ The issues with error responses described in [RFC6733] extend beyond
+ the particular issues for overload control and have been addressed in
+ an ad hoc fashion by various implementations. Addressing these in a
+ standard way would be a useful exercise, but it is beyond the scope
+ of this document.
+
+6. Extensibility and Application Independence
+
+ Given the variety of scenarios in which Diameter elements can be
+ deployed and the variety of roles they can fulfill with Diameter and
+ other technologies, a single algorithm for handling overload may not
+ be sufficient. For purposes of this discussion, an algorithm is
+ inclusive of behavior for control of overload but does not encompass
+ the general mechanism for transporting control information. This
+ effort cannot anticipate all possible future scenarios and roles.
+ Extensibility, particularly of algorithms used to deal with overload,
+ will be important to cover these cases.
+
+
+
+McMurry & Campbell Informational [Page 19]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ Similarly, the scopes to which overload information may apply may
+ include cases that have not yet been considered. Extensibility in
+ this area will also be important.
+
+ The basic mechanism is intended to be application independent, that
+ is, a Diameter node can use it across any existing and future
+ Diameter applications and expect reasonable results. Certain
+ Diameter applications might, however, benefit from application-
+ specific behavior over and above the mechanism's defaults. For
+ example, an application specification might specify relative
+ priorities of messages or selection of a specific overload control
+ algorithm.
+
+7. Solution Requirements
+
+ This section proposes requirements for an improved mechanism to
+ control Diameter overload, with the goals of addressing the issues
+ described in Section 5 and supporting the scenarios described in
+ Section 2. These requirements are stated primarily in terms of
+ individual node behavior to inform the design of the improved
+ mechanism; solution designers should keep in mind that the overall
+ goal is improved overall system behavior across all the nodes
+ involved, not just improved behavior from specific individual nodes.
+
+7.1. General
+
+ REQ 1: The solution MUST provide a communication method for Diameter
+ nodes to exchange load and overload information.
+
+ REQ 2: The solution MUST allow Diameter nodes to support overload
+ control regardless of which Diameter applications they
+ support. Diameter clients and agents must be able to use the
+ received load and overload information to support graceful
+ behavior during an overload condition. Graceful behavior
+ under overload conditions is best described by REQ 3.
+
+ REQ 3: The solution MUST limit the impact of overload on the overall
+ useful throughput of a Diameter server, even when the
+ incoming load on the network is far in excess of its
+ capacity. The overall useful throughput under load is the
+ ultimate measure of the value of a solution.
+
+ REQ 4: Diameter allows requests to be sent from either side of a
+ connection, and either side of a connection may have need to
+ provide its overload status. The solution MUST allow each
+ side of a connection to independently inform the other of its
+ overload status.
+
+
+
+
+McMurry & Campbell Informational [Page 20]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ REQ 5: Diameter allows nodes to determine their peers via dynamic
+ discovery or manual configuration. The solution MUST work
+ consistently without regard to how peers are determined.
+
+ REQ 6: The solution designers SHOULD seek to minimize the amount of
+ new configuration required in order to work. For example, it
+ is better to allow peers to advertise or negotiate support
+ for the solution, rather than to require that this knowledge
+ be configured at each node.
+
+7.2. Performance
+
+ REQ 7: The solution and any associated default algorithm(s) MUST
+ ensure that the system remains stable. At some point after
+ an overload condition has ended, the solution MUST enable
+ capacity to stabilize and become equal to what it would be in
+ the absence of an overload condition. Note that this also
+ requires that the solution MUST allow nodes to shed load
+ without introducing non-converging oscillations during or
+ after an overload condition.
+
+ REQ 8: Supporting nodes MUST be able to distinguish current overload
+ information from stale information.
+
+ REQ 9: The solution MUST function across fully loaded as well as
+ quiescent transport connections. This is partially derived
+ from the requirement for stability in REQ 7.
+
+ REQ 10: Consumers of overload information MUST be able to determine
+ when the overload condition improves or ends.
+
+ REQ 11: The solution MUST be able to operate in networks of different
+ sizes.
+
+ REQ 12: When a single network node fails, goes into overload, or
+ suffers from reduced processing capacity, the solution MUST
+ make it possible to limit the impact of the affected node on
+ other nodes in the network. This helps to prevent a small-
+ scale failure from becoming a widespread outage.
+
+ REQ 13: The solution MUST NOT introduce substantial additional work
+ for a node in an overloaded state. For example, a
+ requirement for an overloaded node to send overload
+ information every time it received a new request would
+ introduce substantial work.
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 21]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ REQ 14: Some scenarios that result in overload involve a rapid
+ increase of traffic with little time between normal levels
+ and levels that induce overload. The solution SHOULD provide
+ for rapid feedback when traffic levels increase.
+
+ REQ 15: The solution MUST NOT interfere with the congestion control
+ mechanisms of underlying transport protocols. For example, a
+ solution that opened additional TCP connections when the
+ network is congested would reduce the effectiveness of the
+ underlying congestion control mechanisms.
+
+7.3. Heterogeneous Support for Solution
+
+ REQ 16: The solution is likely to be deployed incrementally. The
+ solution MUST support a mixed environment where some, but not
+ all, nodes implement it.
+
+ REQ 17: In a mixed environment with nodes that support the solution
+ and nodes that do not, the solution MUST NOT result in
+ materially less useful throughput during overload as would
+ have resulted if the solution were not present. It SHOULD
+ result in less severe overload in this environment.
+
+ REQ 18: In a mixed environment of nodes that support the solution and
+ nodes that do not, the solution MUST NOT preclude elements
+ that support overload control from treating elements that do
+ not support overload control in an equitable fashion relative
+ to those that do. Users and operators of nodes that do not
+ support the solution MUST NOT unfairly benefit from the
+ solution. The solution specification SHOULD provide guidance
+ to implementors for dealing with elements not supporting
+ overload control.
+
+ REQ 19: It MUST be possible to use the solution between nodes in
+ different realms and in different administrative domains.
+
+ REQ 20: Any explicit overload indication MUST be clearly
+ distinguishable from other errors reported via Diameter.
+
+ REQ 21: In cases where a network node fails, is so overloaded that it
+ cannot process messages, or cannot communicate due to a
+ network failure, it may not be able to provide explicit
+ indications of the nature of the failure or its levels of
+ overload. The solution MUST result in at least as much
+ useful throughput as would have resulted if the solution were
+ not in place.
+
+
+
+
+
+McMurry & Campbell Informational [Page 22]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+7.4. Granular Control
+
+ REQ 22: The solution MUST provide a way for a node to throttle the
+ amount of traffic it receives from a peer node. This
+ throttling SHOULD be graded so that it can be applied
+ gradually as offered load increases. Overload is not a
+ binary state; there may be degrees of overload.
+
+ REQ 23: The solution MUST provide sufficient information to enable a
+ load-balancing node to divert messages that are rejected or
+ otherwise throttled by an overloaded upstream node to other
+ upstream nodes that are the most likely to have sufficient
+ capacity to process them.
+
+ REQ 24: The solution MUST provide a mechanism for indicating load
+ levels, even when not in an overload condition, to assist
+ nodes in making decisions to prevent overload conditions from
+ occurring.
+
+7.5. Priority and Policy
+
+ REQ 25: The base specification for the solution SHOULD offer general
+ guidance on which message types might be desirable to send or
+ process over others during times of overload, based on
+ application-specific considerations. For example, it may be
+ more beneficial to process messages for existing sessions
+ ahead of new sessions. Some networks may have a requirement
+ to give priority to requests associated with emergency
+ sessions. Any normative or otherwise detailed definition of
+ the relative priorities of message types during an overload
+ condition will be the responsibility of the application
+ specification.
+
+ REQ 26: The solution MUST NOT prevent a node from prioritizing
+ requests based on any local policy, so that certain requests
+ are given preferential treatment, given additional
+ retransmission, not throttled, or processed ahead of others.
+
+7.6. Security
+
+ REQ 27: The solution MUST NOT provide new vulnerabilities to
+ malicious attack or increase the severity of any existing
+ vulnerabilities. This includes vulnerabilities to DoS and
+ DDoS attacks as well as replay and man-in-the-middle attacks.
+ Note that the Diameter base specification [RFC6733] lacks
+ end-to-end security, and this must be considered (see
+ Security Considerations in this document (Section 8)). Note
+
+
+
+
+McMurry & Campbell Informational [Page 23]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ that this requirement was expressed at a high level so as to
+ not preclude any particular solution. Is is expected that
+ the solution will address this in more detail.
+
+ REQ 28: The solution MUST NOT depend on being deployed in
+ environments where all Diameter nodes are completely trusted.
+ It SHOULD operate as effectively as possible in environments
+ where other nodes are malicious; this includes preventing
+ malicious nodes from obtaining more than a fair share of
+ service. Note that this does not imply any responsibility on
+ the solution to detect, or take countermeasures against,
+ malicious nodes.
+
+ REQ 29: It MUST be possible for a supporting node to make
+ authorization decisions about what information will be sent
+ to peer nodes based on the identity of those nodes. This
+ allows a domain administrator who considers the load of their
+ nodes to be sensitive information to restrict access to that
+ information. Of course, in such cases, there is no
+ expectation that the solution itself will help prevent
+ overload from that peer node.
+
+ REQ 30: The solution MUST NOT interfere with any Diameter-compliant
+ method that a node may use to protect itself from overload
+ from non-supporting nodes or from denial-of-service attacks.
+
+7.7. Flexibility and Extensibility
+
+ REQ 31: There are multiple situations where a Diameter node may be
+ overloaded for some purposes but not others. For example,
+ this can happen to an agent or server that supports multiple
+ applications, or when a server depends on multiple external
+ resources, some of which may become overloaded while others
+ are fully available. The solution MUST allow Diameter nodes
+ to indicate overload with sufficient granularity to allow
+ clients to take action based on the overloaded resources
+ without unreasonably forcing available capacity to go unused.
+ The solution MUST support specification of overload
+ information with granularities of at least "Diameter node",
+ "realm", and "Diameter application" and MUST allow
+ extensibility for others to be added in the future.
+
+ REQ 32: The solution MUST provide a method for extending the
+ information communicated and the algorithms used for overload
+ control.
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 24]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ REQ 33: The solution MUST provide a default algorithm that is
+ mandatory to implement.
+
+ REQ 34: The solution SHOULD provide a method for exchanging overload
+ and load information between elements that are connected by
+ intermediaries that do not support the solution.
+
+8. Security Considerations
+
+ A Diameter overload control mechanism is primarily concerned with the
+ load-related and overload-related behavior of nodes in a Diameter
+ network, and the information used to affect that behavior. Load and
+ overload information is shared between nodes and directly affects the
+ behavior, and thus the information is potentially vulnerable to a
+ number of methods of attack.
+
+ Load and overload information may also be sensitive from both
+ business and network protection viewpoints. Operators of Diameter
+ equipment want to control the visibility of load and overload
+ information to keep it from being used for competitive intelligence
+ or for targeting attacks. It is also important that the Diameter
+ overload control mechanism not introduce any way in which any other
+ information carried by Diameter is sent inappropriately.
+
+ Note that the Diameter base specification [RFC6733] lacks end-to-end
+ security, making it difficult for non-adjacent nodes to verify the
+ authenticity and ownership of load and overload information.
+ Authentication of load and overload information helps to alleviate
+ several of the security issues listed in this section.
+
+ This document includes requirements intended to mitigate the effects
+ of attacks and to protect the information used by the mechanism.
+ This section discusses potential security considerations for overload
+ control solutions. This discussion provides the motivation for
+ several normative requirements described in Section 7. The
+ discussion includes specific references to the normative requirements
+ that apply for each issue.
+
+8.1. Access Control
+
+ To control the visibility of load and overload information, sending
+ should be subject to some form of authentication and authorization of
+ the receiver. It is also important to the receivers that they are
+ confident the load and overload information they receive is from a
+ legitimate source. REQ 28 requires that the solution work without
+ assuming that all Diameter nodes in a network are trusted for the
+ purposes of exchanging overload and load information. REQ 29
+ requires that the solution let nodes restrict unauthorized parties
+
+
+
+McMurry & Campbell Informational [Page 25]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ from seeing overload information. Note that this implies a certain
+ amount of configurability on the nodes supporting the Diameter
+ overload control mechanism.
+
+8.2. Denial-of-Service Attacks
+
+ An overload control mechanism provides a very attractive target for
+ denial-of-service attacks. A small number of messages may effect a
+ large service disruption by falsely reporting overload conditions.
+ Alternately, attacking servers nearing, or in, overload may also be
+ facilitated by disrupting their overload indications, potentially
+ preventing them from mitigating their overload condition.
+
+ A design goal for the Diameter overload control mechanism is to
+ minimize or eliminate the possibility of using the mechanism for this
+ type of attack. More strongly, REQ 27 forbids the solution from
+ introducing new vulnerabilities to malicious attack. Additionally,
+ REQ 30 stipulates that the solution not interfere with other
+ mechanisms used for protection against denial-of-service attacks.
+
+ As the intent of some denial-of-service attacks is to induce overload
+ conditions, an effective overload control mechanism should help to
+ mitigate the effects of such an attack.
+
+8.3. Replay Attacks
+
+ An attacker that has managed to obtain some messages from the
+ overload control mechanism may attempt to affect the behavior of
+ nodes supporting the mechanism by sending those messages at
+ potentially inopportune times. In addition to time shifting, replay
+ attacks may send messages to other nodes as well (target shifting).
+
+ A design goal for the Diameter overload control solution is to
+ minimize or eliminate the possibility of causing disruption by using
+ a replay attack on the Diameter overload control mechanism.
+ (Allowing a replay attack using the overload control solution would
+ violate REQ 27.)
+
+8.4. Man-in-the-Middle Attacks
+
+ By inserting themselves between two nodes supporting the Diameter
+ overload control mechanism, an attacker may potentially both access
+ and alter the information sent between those nodes. This can be used
+ for information gathering for business intelligence and attack
+ targeting, as well as direct attacks.
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 26]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ REQs 27, 28, and 29 imply a need to prevent man-in-the-middle attacks
+ on the overload control solution. A transport using Transport Layer
+ Security (TLS) and/or IPsec may be desirable for this purpose.
+
+8.5. Compromised Hosts
+
+ A compromised host that supports the Diameter overload control
+ mechanism could be used for information gathering as well as for
+ sending malicious information to any Diameter node that would
+ normally accept information from it. While it is beyond the scope of
+ the Diameter overload control mechanism to mitigate any operational
+ interruption to the compromised host, REQs 28 and 29 imply a need to
+ minimize the impact that a compromised host can have on other nodes
+ through the use of the Diameter overload control mechanism. Of
+ course, a compromised host could be used to cause damage in a number
+ of other ways. This is out of scope for a Diameter overload control
+ mechanism.
+
+9. References
+
+9.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC6733] Fajardo, V., Arkko, J., Loughney, J., and G. Zorn,
+ "Diameter Base Protocol", RFC 6733, October 2012.
+
+ [RFC2914] Floyd, S., "Congestion Control Principles", BCP 41,
+ RFC 2914, September 2000.
+
+ [RFC3539] Aboba, B. and J. Wood, "Authentication, Authorization and
+ Accounting (AAA) Transport Profile", RFC 3539, June 2003.
+
+9.2. Informative References
+
+ [RFC5390] Rosenberg, J., "Requirements for Management of Overload
+ in the Session Initiation Protocol", RFC 5390,
+ December 2008.
+
+ [RFC6357] Hilt, V., Noel, E., Shen, C., and A. Abdelal, "Design
+ Considerations for Session Initiation Protocol (SIP)
+ Overload Control", RFC 6357, August 2011.
+
+ [TR23.843] 3GPP, "Study on Core Network (CN) overload solutions",
+ TR 23.843 1.2.0, Work in Progress, October 2013.
+
+
+
+
+
+McMurry & Campbell Informational [Page 27]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+ [IR.34] GSMA, "Inter-Service Provider IP Backbone Guidelines",
+ IR 34 9.1, May 2013.
+
+ [IR.88] GSMA, "LTE Roaming Guidelines", IR 88 9.0, January 2013.
+
+ [IR.92] GSMA, "IMS Profile for Voice and SMS", IR 92 7.0,
+ March 2013.
+
+ [TS23.002] 3GPP, "Network Architecture", TS 23.002 12.2.0,
+ June 2013.
+
+ [TS29.272] 3GPP, "Evolved Packet System (EPS); Mobility Management
+ Entity (MME) and Serving GPRS Support Node (SGSN) related
+ interfaces based on Diameter protocol", TS 29.272 12.2.0,
+ September 2013.
+
+ [TS29.212] 3GPP, "Policy and Charging Control (PCC) over Gx/Sd
+ reference point", TS 29.212 12.2.0, September 2013.
+
+ [TS29.228] 3GPP, "IP Multimedia (IM) Subsystem Cx and Dx interfaces;
+ Signalling flows and message contents", TS 29.228 12.0.0,
+ September 2013.
+
+ [TS29.002] 3GPP, "Mobile Application Part (MAP) specification",
+ TS 29.002 12.2.0, September 2013.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 28]
+
+RFC 7068 Diameter Overload Control Requirements November 2013
+
+
+Appendix A. Contributors
+
+ Significant contributions to this document were made by Adam Roach
+ and Eric Noel.
+
+Appendix B. Acknowledgements
+
+ Review of, and contributions to, this specification by Martin Dolly,
+ Carolyn Johnson, Jianrong Wang, Imtiaz Shaikh, Jouni Korhonen, Robert
+ Sparks, Dieter Jacobsohn, Janet Gunn, Jean-Jacques Trottin, Laurent
+ Thiebaut, Andrew Booth, and Lionel Morand were most appreciated. We
+ would like to thank them for their time and expertise.
+
+Authors' Addresses
+
+ Eric McMurry
+ Oracle
+ 17210 Campbell Rd.
+ Suite 250
+ Dallas, TX 75252
+ US
+
+
+
+ Ben Campbell
+ Oracle
+ 17210 Campbell Rd.
+ Suite 250
+ Dallas, TX 75252
+ US
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McMurry & Campbell Informational [Page 29]
+
diff --git a/lib/diameter/doc/standard/rfc7075.txt b/lib/diameter/doc/standard/rfc7075.txt
new file mode 100644
index 0000000000..f5fd905e72
--- /dev/null
+++ b/lib/diameter/doc/standard/rfc7075.txt
@@ -0,0 +1,563 @@
+
+
+
+
+
+
+Internet Engineering Task Force (IETF) T. Tsou
+Request for Comments: 7075 Huawei Technologies (USA)
+Updates: 6733 R. Hao
+Category: Standards Track Comcast Cable
+ISSN: 2070-1721 T. Taylor, Ed.
+ Huawei Technologies
+ November 2013
+
+
+ Realm-Based Redirection In Diameter
+
+Abstract
+
+ The Diameter protocol includes a capability for message redirection,
+ controlled by an application-independent "redirect agent". In some
+ circumstances, an operator may wish to redirect messages to an
+ alternate domain without specifying individual hosts. This document
+ specifies an application-specific mechanism by which a Diameter
+ server or proxy (node) can perform such a redirection when the
+ Straightforward-Naming Authority Pointer (S-NAPTR) is not used for
+ dynamic peer discovery. A node performing this new function is
+ referred to as a "Realm-based Redirect Server".
+
+ This memo updates Sections 6.13 and 6.14 of RFC 6733 with respect to
+ the usage of the Redirect-Host-Usage and Redirect-Max-Cache-Time
+ Attribute-Value Pairs (AVPs).
+
+Status of This Memo
+
+ This is an Internet Standards Track document.
+
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 5741.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ http://www.rfc-editor.org/info/rfc7075.
+
+
+
+
+
+
+
+
+
+
+
+Tsou, et al. Standards Track [Page 1]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+Copyright Notice
+
+ Copyright (c) 2013 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 1.1. Terminology . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Support of Realm-Based Redirection Within Applications . . . 4
+ 3. Realm-Based Redirection . . . . . . . . . . . . . . . . . . . 5
+ 3.1. Configuration of the Realm-Based Redirect Server . . . . 5
+ 3.2. Behavior of Diameter Nodes . . . . . . . . . . . . . . . 6
+ 3.2.1. Behavior at the Realm-Based Redirect Server . . . . . 6
+ 3.2.2. Proxy Behavior . . . . . . . . . . . . . . . . . . . 6
+ 3.2.3. Client Behavior . . . . . . . . . . . . . . . . . . . 7
+ 3.3. The Redirect-Realm AVP . . . . . . . . . . . . . . . . . 7
+ 3.4. DIAMETER_REALM_REDIRECT_INDICATION Protocol Error Code . 7
+ 4. Security Considerations . . . . . . . . . . . . . . . . . . . 8
+ 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8
+ 6. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 9
+ 7. References . . . . . . . . . . . . . . . . . . . . . . . . . 9
+ 7.1. Normative References . . . . . . . . . . . . . . . . . . 9
+ 7.2. Informative References . . . . . . . . . . . . . . . . . 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Tsou, et al. Standards Track [Page 2]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+1. Introduction
+
+ The Diameter base protocol [RFC6733] specifies a basic redirection
+ service provided by a redirect agent. The redirect indication
+ returned by the redirect agent is described in Section 6.1.8 and
+ Sections 6.12 through 6.14 of [RFC6733]. It provides one or more
+ individual hosts to the message sender as the destination of the
+ redirected message.
+
+ However, consider the case where an operator has offered a specific
+ service but no longer wishes to do so. The operator has arranged for
+ an alternative domain to provide the service. To aid in the
+ transition to the new arrangement, the original operator maintains a
+ redirect server to indicate to the message sender the alternative
+ domain to which the redirect the request should be sent. However,
+ the original operator should not have to configure the redirect
+ server with a list of hosts to contact in the alternative operator's
+ domain; the original operator should simply be able to provide
+ redirect indications to the domain as a whole.
+
+1.1. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+ Within this specification, the term "realm-based redirection" is used
+ to refer to a mode of operation where a realm, rather than an
+ individual host, is returned as the redirect indication.
+
+ The term "Realm-based Redirect Server" denotes the Diameter node
+ (Diameter server or proxy) that returns the realm-based redirection.
+ The behavior of the Realm-based Redirect Server itself is a slight
+ modification to the behavior of a basic redirect agent as described
+ in Section 6.1.8 of [RFC6733].
+
+ The use of a number of terms in this document is consistent with the
+ usage in [RFC6733]: "Diameter client", "Diameter node", "Diameter
+ peer", "Diameter server", "proxy", "realm" or "domain", "redirect
+ agent", and "session" as defined in Section 1.2, and "application" as
+ defined implicitly by Sections 1.3.4, 2.3, and 2.4.
+
+
+
+
+
+
+
+
+
+
+Tsou, et al. Standards Track [Page 3]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+2. Support of Realm-Based Redirection Within Applications
+
+ The DNS-based dynamic peer discovery mechanism defined in the
+ Diameter base protocol [RFC6733] provides a simple mechanism for
+ realm-based redirection using the S-NAPTR DDDS application [RFC3958].
+ When S-NAPTR is used for peer discovery, redirection of Diameter
+ requests from the original realm to a new realm may be performed by
+ updating the existing NAPTR resource records (RRs) for the original
+ realm as follows: the NAPTR RR for the desired application(s) and
+ supported application protocol(s) provided by the new realm will have
+ an empty FLAG field and the REPLACEMENT field will contain the new
+ realm to use for the next DNS lookup. The new realm can be
+ arbitrary; the restriction in [RFC6733] that the NAPTR replacement
+ field match the domain of the original query does not apply for
+ realm-based redirect purposes.
+
+ However, the use of DNS-based dynamic peer discovery is optional for
+ Diameter implementations. For deployments that do not make use of
+ S-NAPTR peer discovery, support of realm-based redirection needs to
+ be specified as part of the functionality supported by a Diameter
+ application. In this way, support of the considered Diameter
+ application (discovered during capabilities exchange phase as defined
+ in Diameter base protocol [RFC6733]) indicates implicit support of
+ the realm-based redirection mechanism. A new application
+ specification can incorporate the mechanism specified here by making
+ it mandatory to implement for the application and referencing this
+ specification normatively.
+
+ The result of making realm-based redirection an application-specific
+ behavior is that it cannot be performed by a redirect agent as
+ defined in [RFC6733], but MUST be performed instead by an
+ application-aware Diameter node (Diameter server or proxy) (hereafter
+ called a "Realm-based Redirect Server").
+
+ An application can specify that realm-based redirection operates only
+ on complete sessions beginning with the initial message or on every
+ message within the application, even if earlier messages of the same
+ session were not redirected. This distinction matters only when
+ realm-based redirection is first initiated. In the former case,
+ existing sessions will not be disrupted by the deployment of realm-
+ based redirection. In the latter case, existing sessions will be
+ disrupted if they are stateful.
+
+
+
+
+
+
+
+
+
+Tsou, et al. Standards Track [Page 4]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+3. Realm-Based Redirection
+
+ This section specifies an extension of the Diameter base protocol
+ [RFC6733] to achieve realm-based redirection. The elements of this
+ solution are:
+
+ o a new result code, DIAMETER_REALM_REDIRECT_INDICATION (3011);
+
+ o a new attribute-value pair (AVP), Redirect-Realm (620); and
+
+ o associated behavior at Diameter nodes implementing this
+ specification.
+
+ This behavior includes the optional use of the Redirect-Host-Usage
+ and Redirect-Max-Cache-Time AVPs. In this document, these AVPs apply
+ to the peer discovered by a node acting on the redirect server's
+ response, an extension to their normal usage as described in Sections
+ 6.13 and 6.14 of [RFC6733].
+
+ Section 3.2.2 and Section 3.2.3 describe how a proxy or client may
+ update its routing table for the application and initial realm as a
+ result of selecting a peer in the new realm after realm-based
+ redirection. Note that as a result, the proxy or client will
+ automatically route subsequent requests for that application to the
+ new realm (with the possible exception of requests within sessions
+ already established with the initial realm) until the cached routing
+ entry expires. This should be borne in mind if the rerouting is
+ intended to be temporary.
+
+3.1. Configuration of the Realm-Based Redirect Server
+
+ A Diameter node (Diameter server or proxy) acting as a Realm-based
+ Redirect Server MUST be configured as follows to execute realm-based
+ redirection:
+
+ o configured with an application that incorporates realm-based
+ redirection;
+
+ o the Local Action field of the routing table described in
+ Section 2.7 of [RFC6733] is set to LOCAL;
+
+ o an application-specific field is set to indicate that the required
+ local action is to perform realm-based redirection;
+
+ o an associated application-specific field is configured with the
+ identities of one or more realms to which the request should be
+ redirected.
+
+
+
+
+Tsou, et al. Standards Track [Page 5]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+3.2. Behavior of Diameter Nodes
+
+3.2.1. Behavior at the Realm-Based Redirect Server
+
+ As mentioned in Section 2, an application can specify that realm-
+ based redirection operates only on complete sessions beginning with
+ the initial message (i.e., to prevent disruption of established
+ sessions) or on every message within the application, even if earlier
+ messages of the same session were not redirected.
+
+ If a Realm-based Redirect Server configured as described in
+ Section 3.1 receives a request to which realm-based redirection
+ applies, the Realm-based Redirect Server MUST reply with an answer
+ message with the 'E' bit set, while maintaining the Hop-by-Hop
+ Identifier in the header. The Realm-based Redirect Server MUST
+ include the Result-Code AVP set to
+ DIAMETER_REALM_REDIRECT_INDICATION. The Realm-based Redirect Server
+ MUST also include the alternate realm identifier(s) with which it has
+ been configured, each in a separate Redirect-Realm AVP instance.
+
+ The Realm-based Redirect Server MAY include a copy of the Redirect-
+ Host-Usage AVP, which SHOULD be set to REALM_AND_APPLICATION. If
+ this AVP is added, the Redirect-Max-Cache-Time AVP MUST also be
+ included. Note that these AVPs apply to the peer discovered by a
+ node acting on the Realm-based Redirect Server's response as
+ described in the next section. This is an extension of their normal
+ usage as described by Sections 6.13 and 6.14 of [RFC6733].
+
+ Realm-based redirection MAY be applied even if a Destination-Host
+ AVP is present in the request, depending on the operator-based
+ policy.
+
+3.2.2. Proxy Behavior
+
+ A proxy conforming to this specification that receives an answer
+ message with the Result-Code AVP set to
+ DIAMETER_REALM_REDIRECT_INDICATION MUST attempt to reroute the
+ original request to a server in a realm identified by a Redirect-
+ Realm AVP instance in the answer message, and if it fails MUST
+ forward the indication toward the client. To reroute the request, it
+ MUST take the following actions:
+
+ 1. Select a specific realm from amongst those identified in
+ instances of the Redirect-Realm AVP in the answer message.
+
+ 2. If successful, locate and establish a route to a peer in the
+ realm given by the Redirect-Realm AVP, using normal discovery
+ procedures as described in Section 5.2 of [RFC6733].
+
+
+
+Tsou, et al. Standards Track [Page 6]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+ 3. If again successful:
+
+ A. update its cache of routing entries for the realm and
+ application to which the original request was directed,
+ taking into account the Redirect-Host-Usage and Redirect-Max-
+ Cache-Time AVPs, if present in the answer.
+
+ B. Remove the Destination-Host (if present) and Destination-
+ Realm AVPs from the original request and add a new
+ Destination-Realm AVP containing the realm selected in the
+ initial step.
+
+ C. Forward the modified request.
+
+ 4. If either of the preceding steps 2-3 fail and additional realms
+ have been identified in the original answer, select another
+ instance of the Redirect-Realm AVP in that answer and repeat
+ steps 2-3 for the realm that it identifies.
+
+3.2.3. Client Behavior
+
+ A client conforming to this specification MUST be prepared to receive
+ either an answer message containing a Result-Code AVP set to
+ DIAMETER_REALM_REDIRECT_INDICATION, or, as the result of proxy
+ action, some other result from a realm differing from the one to
+ which it sent the original request. In the case where it receives
+ DIAMETER_REALM_REDIRECT_INDICATION, the client SHOULD follow the same
+ steps prescribed in the previous section for a proxy, in order to
+ both update its routing table and obtain service for the original
+ request.
+
+3.3. The Redirect-Realm AVP
+
+ The Redirect-Realm AVP (620) is of type DiameterIdentity. It
+ specifies a realm to which a node receiving a redirect indication
+ containing the result code value DIAMETER_REALM_REDIRECT_INDICATION
+ and the Redirect-Realm AVP SHOULD route the original request.
+
+3.4. DIAMETER_REALM_REDIRECT_INDICATION Protocol Error Code
+
+ The DIAMETER_REALM_REDIRECT_INDICATION (3011) Protocol error code
+ indicates that a server has determined that the request within an
+ application supporting realm-based redirection could not be satisfied
+ locally, and the initiator of the request SHOULD direct the request
+ directly to a peer within a realm that has been identified in the
+ response. When set, the Redirect-Realm AVP MUST be present.
+
+
+
+
+
+Tsou, et al. Standards Track [Page 7]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+4. Security Considerations
+
+ The general recommendations given in Section 13 of the Diameter base
+ protocol [RFC6733] apply. Specific security recommendations related
+ to the realm-based redirection defined in this document are described
+ below.
+
+ Realm-based redirection implies a change in the business relationship
+ between organizations. Before redirecting a request towards a realm
+ different from the initial realm, the client or proxy MUST ensure
+ that the authorization checks have been performed at each connection
+ along the path toward the realm identified in the realm-based
+ redirect indication. Details on Diameter authorization path set-up
+ are given in Section 2.9 of [RFC6733]. Section 13 of [RFC6733]
+ provides recommendations on how to authenticate and secure each peer-
+ to-peer connection (using TLS, DTLS, or IPsec) along the way, thus
+ permitting the necessary hop-by-hop authorization checks.
+
+ Although it is assumed that the administrative domains are secure, a
+ compromised Diameter node acting as a Realm-based Redirect Server
+ would be able to redirect a large number of Diameter requests towards
+ a victim domain that would then be flooded with undesired Diameter
+ requests. Such an attack is nevertheless discouraged by the use of
+ secure Diameter peer-to-peer connections and authorization checks,
+ since these would enable a potential victim domain to discover from
+ where an attack is coming. That in itself, however, does not prevent
+ such a DoS attack.
+
+ Because realm-based redirection defined in this document implies that
+ the Destination-Realm AVP in a client-initiated request can be
+ changed by a Diameter proxy in the path between the client and the
+ server, any cryptographic algorithm that would use the Destination-
+ Realm AVP as input to the calculation performed by the client and the
+ server would be broken by this form of redirection. Application
+ specifications that would rely on such cryptographic algorithms
+ SHOULD NOT incorporate this realm-based redirection.
+
+5. IANA Considerations
+
+ This specification allocates a new AVP code Redirect-Realm (620) in
+ the "AVP Codes" registry under "Authentication, Authorization, and
+ Accounting (AAA) Parameters".
+
+ This specification allocates a new Result-Code value
+ DIAMETER_REALM_REDIRECT_INDICATION (3011) in the "Result-Code AVP
+ Values (code 268) - Protocol Errors" registry under "Authentication,
+ Authorization, and Accounting (AAA) Parameters".
+
+
+
+
+Tsou, et al. Standards Track [Page 8]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+6. Acknowledgements
+
+ Glen Zorn, Sebastien Decugis, Wolfgang Steigerwald, Mark Jones,
+ Victor Fajardo, Jouni Korhonen, Avi Lior, and Lionel Morand
+ contributed comments that helped to shape this document. As
+ shepherd, Lionel contributed a second set of comments that added
+ polish to the document before it was submitted to the IESG. Benoit
+ Claise picked up additional points that were quickly resolved with
+ Lionel's help. During IETF Last Call Review, Enrico Marocco picked
+ up some important editorial corrections. Stefan Winter contributed
+ text on the use of S-NAPTR as an alternative method of realm-based
+ redirection already specified in [RFC6733]. Derek Atkins performed a
+ review on behalf of the Security Directorate. Lionel noted one more
+ correction.
+
+ Finally, this document benefited from comments and discussion raised
+ by IESG members Stewart Bryant, Stephen Farrell, Barry Leiba, Pete
+ Resnick, Jari Arkko, and Sean Turner during IESG review.
+
+ The authors are very grateful to Lionel Morand for his active role as
+ document shepherd. At each stage, he worked to summarize and resolve
+ comments, making the editor's role easy. Thank you.
+
+7. References
+
+7.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC6733] Fajardo, V., Arkko, J., Loughney, J., and G. Zorn,
+ "Diameter Base Protocol", RFC 6733, October 2012.
+
+7.2. Informative References
+
+ [RFC3958] Daigle, L. and A. Newton, "Domain-Based Application
+ Service Location Using SRV RRs and the Dynamic Delegation
+ Discovery Service (DDDS)", RFC 3958, January 2005.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Tsou, et al. Standards Track [Page 9]
+
+RFC 7075 Realm-Based Redirection In Diameter November 2013
+
+
+Authors' Addresses
+
+ Tina Tsou
+ Huawei Technologies (USA)
+ 2330 Central Expressway
+ Santa Clara, CA 95050
+ USA
+
+ Phone: +1 408 330 4424
+ URI: http://tinatsou.weebly.com/contact.html
+
+
+ Ruibing Hao
+ Comcast Cable
+ One Comcast Center
+ Philadelphia, PA 19103
+ USA
+
+ Phone: +1 215 286 3991(O)
+
+
+ Tom Taylor (editor)
+ Huawei Technologies
+ Ottawa
+ Canada
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Tsou, et al. Standards Track [Page 10]
+
diff --git a/lib/diameter/examples/dict/.gitignore b/lib/diameter/examples/dict/.gitignore
new file mode 100644
index 0000000000..feeb378fd8
--- /dev/null
+++ b/lib/diameter/examples/dict/.gitignore
@@ -0,0 +1,2 @@
+
+/depend.mk
diff --git a/lib/diameter/examples/dict/GNUmakefile b/lib/diameter/examples/dict/GNUmakefile
new file mode 100644
index 0000000000..60c95c08f9
--- /dev/null
+++ b/lib/diameter/examples/dict/GNUmakefile
@@ -0,0 +1,60 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2013. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+# Build example dictionaries. Assumes erlc and diameterc are on PATH.
+#
+
+DICTS = rfc4004_mip \
+ rfc4005_nas \
+ rfc4006_cc \
+ rfc4072_eap \
+ rfc4590_digest \
+ rfc4740_sip
+
+FILES = $(DICTS:%=%.dia)
+BEAMS = $(DICTS:%=%.beam)
+
+COMMON = diameter_gen_base_rfc6733
+
+%.erl: %.dia
+ diameterc --name $(basename $@) \
+ --prefix $(basename $@) \
+ --inherits common/$(COMMON) \
+ $<
+
+%.beam: %.erl
+ erlc -Wall +debug_info $<
+
+all: $(BEAMS)
+
+clean:
+ rm -f $(DICTS:%=%.erl) $(DICTS:%=%.hrl) $(BEAMS) depend.mk
+
+-include depend.mk
+
+depend.mk: depend.sed $(FILES) GNUmakefile
+ (for f in $(FILES); do \
+ (echo $$f; cat $$f) | sed -f depend.sed; \
+ done) \
+ > $@
+
+.PHONY: all clean
+
+.SECONDARY: $(DICTS:%=%.erl)
diff --git a/lib/diameter/examples/dict/depend.sed b/lib/diameter/examples/dict/depend.sed
new file mode 100644
index 0000000000..fd9a38479c
--- /dev/null
+++ b/lib/diameter/examples/dict/depend.sed
@@ -0,0 +1,43 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2013. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+# Extract dependencies from .dia files. First line of input is the
+# dictionary's filename, the rest is its contents.
+#
+
+1{
+ s@\.[^.]*$@@
+ h
+ d
+}
+
+# Only interested in @inherits.
+/^@inherits */!d
+
+s///
+s/ .*//
+
+# Ignore the common application.
+/^common$/d
+
+# Retrieve the dictionary name from the hold space and output
+# a dependency.
+G
+s@^\(.*\)\n\(.*\)@\2.erl: \1.beam@
diff --git a/lib/diameter/examples/dict/rfc4004_mip.dia b/lib/diameter/examples/dict/rfc4004_mip.dia
index 575ad4394a..0595cfe9ef 100644
--- a/lib/diameter/examples/dict/rfc4004_mip.dia
+++ b/lib/diameter/examples/dict/rfc4004_mip.dia
@@ -1,7 +1,7 @@
;;
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;; Copyright Ericsson AB 2010-2013. All Rights Reserved.
;;
;; The contents of this file are subject to the Erlang Public License,
;; Version 1.1, (the "License"); you may not use this file except in
@@ -30,7 +30,7 @@
@id 2
-@inherits rfc3588_base
+@inherits common
;; ===========================================================================
diff --git a/lib/diameter/examples/dict/rfc4005_nas.dia b/lib/diameter/examples/dict/rfc4005_nas.dia
index a4b44e38bb..6f0e7c1ce5 100644
--- a/lib/diameter/examples/dict/rfc4005_nas.dia
+++ b/lib/diameter/examples/dict/rfc4005_nas.dia
@@ -1,7 +1,7 @@
;;
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;; Copyright Ericsson AB 2010-2013. All Rights Reserved.
;;
;; The contents of this file are subject to the Erlang Public License,
;; Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,7 @@
@id 1
-@inherits rfc3588_base
+@inherits common
;; ===========================================================================
diff --git a/lib/diameter/examples/dict/rfc4006_cc.dia b/lib/diameter/examples/dict/rfc4006_cc.dia
index b723e4ddbb..b45ffc8090 100644
--- a/lib/diameter/examples/dict/rfc4006_cc.dia
+++ b/lib/diameter/examples/dict/rfc4006_cc.dia
@@ -1,7 +1,7 @@
;;
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;; Copyright Ericsson AB 2010-2013. All Rights Reserved.
;;
;; The contents of this file are subject to the Erlang Public License,
;; Version 1.1, (the "License"); you may not use this file except in
@@ -23,7 +23,7 @@
@id 4
-@inherits rfc3588_base
+@inherits common
@inherits rfc4005_nas Filter-Id
;; ===========================================================================
diff --git a/lib/diameter/examples/dict/rfc4072_eap.dia b/lib/diameter/examples/dict/rfc4072_eap.dia
index 111516b347..676b1b8b9b 100644
--- a/lib/diameter/examples/dict/rfc4072_eap.dia
+++ b/lib/diameter/examples/dict/rfc4072_eap.dia
@@ -1,7 +1,7 @@
;;
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;; Copyright Ericsson AB 2010-2013. All Rights Reserved.
;;
;; The contents of this file are subject to the Erlang Public License,
;; Version 1.1, (the "License"); you may not use this file except in
@@ -30,7 +30,7 @@
@id 5
-@inherits rfc3588_base
+@inherits common
@inherits rfc4005_nas
;; ===========================================================================
diff --git a/lib/diameter/examples/dict/rfc4590_digest.dia b/lib/diameter/examples/dict/rfc4590_digest.dia
index a4ebe0c456..de68a6ef7e 100644
--- a/lib/diameter/examples/dict/rfc4590_digest.dia
+++ b/lib/diameter/examples/dict/rfc4590_digest.dia
@@ -1,7 +1,7 @@
;;
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;; Copyright Ericsson AB 2010-2013. All Rights Reserved.
;;
;; The contents of this file are subject to the Erlang Public License,
;; Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/diameter/examples/dict/rfc4740_sip.dia b/lib/diameter/examples/dict/rfc4740_sip.dia
index 8c21882649..cada3ac826 100644
--- a/lib/diameter/examples/dict/rfc4740_sip.dia
+++ b/lib/diameter/examples/dict/rfc4740_sip.dia
@@ -1,7 +1,7 @@
;;
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;; Copyright Ericsson AB 2010-2013. All Rights Reserved.
;;
;; The contents of this file are subject to the Erlang Public License,
;; Version 1.1, (the "License"); you may not use this file except in
@@ -23,7 +23,7 @@
@id 6
-@inherits rfc3588_base
+@inherits common
@inherits rfc4590_digest
;; ===========================================================================
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index 77200cc7d0..d74e091e11 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -343,7 +343,7 @@ call(SvcName, App, Message) ->
| {capx_timeout, 'Unsigned32'()}
| {disconnect_cb, evaluable()}
| {length_errors, exit | handle | discard}
- | {reconnect_timer, 'Unsigned32'()}
+ | {connect_timer, 'Unsigned32'()}
| {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}}
| {watchdog_config, [{okay|suspect, non_neg_integer()}]}
| {spawn_opt, list()}
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 34b40c3a29..f5ea459fd0 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -537,7 +537,9 @@ opt({capx_timeout, Tmo}) ->
opt({length_errors, T}) ->
lists:member(T, [exit, handle, discard]);
-opt({reconnect_timer, Tmo}) ->
+opt({K, Tmo})
+ when K == reconnect_timer; %% deprecated
+ K == connect_timer ->
?IS_UINT32(Tmo);
opt({watchdog_timer, {M,F,A}})
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 47e03cd0a0..70e66537ed 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1143,10 +1143,17 @@ q_restart(false, _) ->
%% communicate.
default_tc(connect, Opts) ->
- proplists:get_value(reconnect_timer, Opts, ?DEFAULT_TC);
+ connect_timer(Opts, ?DEFAULT_TC);
default_tc(accept, _) ->
0.
+%% Accept both connect_timer and the (older) reconnect_timer, the
+%% latter being a remnant from a time in which the timer did apply to
+%% reconnect attempts.
+connect_timer(Opts, Def0) ->
+ Def = proplists:get_value(reconnect_timer, Opts, Def0),
+ proplists:get_value(connect_timer, Opts, Def).
+
%% Bound tc below if the watchdog was restarted recently to avoid
%% continuous restarted in case of faulty config or other problems.
tc(Time, Tc) ->
@@ -1181,7 +1188,7 @@ tc(false = No, _, _) -> %% removed
%% another watchdog to be able to detect that it should transition
%% from initial into reopen rather than okay. That someone is either
%% the accepting watchdog upon reception of a CER from the previously
-%% connected peer, or us after reconnect_timer timeout.
+%% connected peer, or us after connect_timer timeout.
close(#watchdog{type = connect}, _) ->
ok;
@@ -1194,16 +1201,16 @@ close(#watchdog{type = accept,
%% Tell watchdog to (maybe) die later ...
c(Pid, true, Opts) ->
- Tc = proplists:get_value(reconnect_timer, Opts, 2*?DEFAULT_TC),
+ Tc = connect_timer(Opts, 2*?DEFAULT_TC),
erlang:send_after(Tc, Pid, close);
%% ... or now.
c(Pid, false, _Opts) ->
Pid ! close.
-%% The RFC's only document the behaviour of Tc, our reconnect_timer,
+%% The RFC's only document the behaviour of Tc, our connect_timer,
%% for the establishment of connections but we also give
-%% reconnect_timer semantics for a listener, being the time within
+%% connect_timer semantics for a listener, being the time within
%% which a new connection attempt is expected of a connecting peer.
%% The value should be greater than the peer's Tc + jitter.
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 127a647b89..9a1c8b6585 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -329,7 +329,7 @@ code_change(_, State, _) ->
%% the commentary is ours.
%% Service or watchdog is telling the watchdog of an accepting
-%% transport to die after reconnect_timer expiry or reestablished
+%% transport to die after connect_timer expiry or reestablished
%% connection (in another transport process) respectively.
transition(close, #watchdog{status = down}) ->
{{accept, _}, _, _} = getr(restart), %% assert
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index e687145263..22422f2ef2 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -33,11 +33,6 @@
-export([from_dict/4]).
-%% Internal exports (for test).
--export([file/1,
- file/2,
- file/3]).
-
-include("diameter_forms.hrl").
-include("diameter_vsn.hrl").
@@ -48,18 +43,61 @@
%% ===========================================================================
--spec from_dict(File, Spec, Opts, Mode)
+-spec from_dict(File, ParseD, Opts, Mode)
-> ok
+ | term()
when File :: string(),
- Spec :: orddict:orddict(),
+ ParseD :: orddict:orddict(),
Opts :: list(),
- Mode :: spec | erl | hrl.
+ Mode :: parse | forms | erl | hrl.
-from_dict(File, Spec, Opts, Mode) ->
+from_dict(File, ParseD, Opts, Mode) ->
Outdir = proplists:get_value(outdir, Opts, "."),
+ Return = proplists:get_value(return, Opts, false),
+ Mod = mod(File, orddict:find(name, ParseD)),
putr(verbose, lists:member(verbose, Opts)),
- putr(debug, lists:member(debug, Opts)),
- codegen(File, Spec, Outdir, Mode).
+ try
+ maybe_write(Return, Mode, Outdir, Mod, gen(Mode, ParseD, ?A(Mod)))
+ after
+ eraser(verbose)
+ end.
+
+mod(File, error) ->
+ filename:rootname(filename:basename(File));
+mod(_, {ok, Mod}) ->
+ Mod.
+
+maybe_write(true, _, _, _, T) ->
+ T;
+
+maybe_write(_, Mode, Outdir, Mod, T) ->
+ Path = filename:join(Outdir, Mod), %% minus extension
+ do_write(Mode, [Path, $., ext(Mode)], T).
+
+ext(parse) ->
+ "D";
+ext(forms) ->
+ "F";
+ext(T) ->
+ ?S(T).
+
+do_write(M, Path, T)
+ when M == parse;
+ M == forms ->
+ write_term(Path, T);
+do_write(_, Path, T) ->
+ write(Path, T).
+
+write(Path, T) ->
+ write(Path, "~s", T).
+
+write_term(Path, T) ->
+ write(Path, "~p.~n", T).
+
+write(Path, Fmt, T) ->
+ {ok, Fd} = file:open(Path, [write]),
+ io:fwrite(Fd, Fmt, [T]),
+ ok = file:close(Fd).
%% Optional reports when running verbosely.
report(What, Data) ->
@@ -77,20 +115,8 @@ putr(Key, Value) ->
getr(Key) ->
get({?MODULE, Key}).
-%% ===========================================================================
-%% ===========================================================================
-
-%% Generate from parsed dictionary in a file.
-
-file(F) ->
- file(F, spec).
-
-file(F, Mode) ->
- file(F, ".", Mode).
-
-file(F, Outdir, Mode) ->
- {ok, [Spec]} = file:consult(F),
- from_dict(F, Spec, Outdir, Mode).
+eraser(Key) ->
+ erase({?MODULE, Key}).
%% ===========================================================================
%% ===========================================================================
@@ -98,97 +124,68 @@ file(F, Outdir, Mode) ->
get_value(Key, Plist) ->
proplists:get_value(Key, Plist, []).
-write(Path, Str) ->
- w(Path, Str, "~s").
-
-write_term(Path, T) ->
- w(Path, T, "~p.").
-
-w(Path, T, Fmt) ->
- {ok, Fd} = file:open(Path, [write]),
- io:fwrite(Fd, Fmt ++ "~n", [T]),
- file:close(Fd).
-
-codegen(File, Spec, Outdir, Mode) ->
- Mod = mod(File, orddict:find(name, Spec)),
- Path = filename:join(Outdir, Mod), %% minus extension
- gen(Mode, Spec, ?A(Mod), Path),
- ok.
-
-mod(File, error) ->
- filename:rootname(filename:basename(File));
-mod(_, {ok, Mod}) ->
- Mod.
-
-gen(spec, Spec, _Mod, Path) ->
- write_term(Path ++ ".spec", [?VERSION | Spec]);
-
-gen(hrl, Spec, Mod, Path) ->
- gen_hrl(Path ++ ".hrl", Mod, Spec);
-
-gen(erl, Spec, Mod, Path) ->
- Forms = [{?attribute, module, Mod},
- {?attribute, compile, {parse_transform, diameter_exprecs}},
- {?attribute, compile, nowarn_unused_function},
- {?attribute, export, [{name, 0},
- {id, 0},
- {vendor_id, 0},
- {vendor_name, 0},
- {decode_avps, 2}, %% in diameter_gen.hrl
- {encode_avps, 2}, %%
- {msg_name, 2},
- {msg_header, 1},
- {rec2msg, 1},
- {msg2rec, 1},
- {name2rec, 1},
- {avp_name, 2},
- {avp_arity, 2},
- {avp_header, 1},
- {avp, 3},
- {grouped_avp, 3},
- {enumerated_avp, 3},
- {empty_value, 1},
- {dict, 0}]},
- %% diameter.hrl is included for #diameter_avp
- {?attribute, include_lib, "diameter/include/diameter.hrl"},
- {?attribute, include_lib, "diameter/include/diameter_gen.hrl"},
- f_name(Mod),
- f_id(Spec),
- f_vendor_id(Spec),
- f_vendor_name(Spec),
- f_msg_name(Spec),
- f_msg_header(Spec),
- f_rec2msg(Spec),
- f_msg2rec(Spec),
- f_name2rec(Spec),
- f_avp_name(Spec),
- f_avp_arity(Spec),
- f_avp_header(Spec),
- f_avp(Spec),
- f_enumerated_avp(Spec),
- f_empty_value(Spec),
- f_dict(Spec),
- {eof, ?LINE}],
-
- gen_erl(Path, insert_hrl_forms(Spec, Forms)).
-
-gen_erl(Path, Forms) ->
- getr(debug) andalso write_term(Path ++ ".forms", Forms),
- write(Path ++ ".erl",
- header() ++ erl_prettypr:format(erl_syntax:form_list(Forms))).
-
-insert_hrl_forms(Spec, Forms) ->
- {H,T} = lists:splitwith(fun is_header/1, Forms),
- H ++ make_hrl_forms(Spec) ++ T.
-
-is_header({attribute, _, export, _}) ->
- false;
-is_header(_) ->
- true.
-
-make_hrl_forms(Spec) ->
+gen(parse, ParseD, _Mod) ->
+ [?VERSION | ParseD];
+
+gen(forms, ParseD, Mod) ->
+ pp(erl_forms(Mod, ParseD));
+
+gen(hrl, ParseD, Mod) ->
+ gen_hrl(Mod, ParseD);
+
+gen(erl, ParseD, Mod) ->
+ [header(), prettypr(erl_forms(Mod, ParseD)), $\n].
+
+erl_forms(Mod, ParseD) ->
+ Forms = [[{?attribute, module, Mod},
+ {?attribute, compile, {parse_transform, diameter_exprecs}},
+ {?attribute, compile, nowarn_unused_function}],
+ make_hrl_forms(ParseD),
+ [{?attribute, export, [{name, 0},
+ {id, 0},
+ {vendor_id, 0},
+ {vendor_name, 0},
+ {decode_avps, 2}, %% in diameter_gen.hrl
+ {encode_avps, 2}, %%
+ {msg_name, 2},
+ {msg_header, 1},
+ {rec2msg, 1},
+ {msg2rec, 1},
+ {name2rec, 1},
+ {avp_name, 2},
+ {avp_arity, 2},
+ {avp_header, 1},
+ {avp, 3},
+ {grouped_avp, 3},
+ {enumerated_avp, 3},
+ {empty_value, 1},
+ {dict, 0}]},
+ %% diameter.hrl is included for #diameter_avp
+ {?attribute, include_lib, "diameter/include/diameter.hrl"},
+ {?attribute, include_lib, "diameter/include/diameter_gen.hrl"},
+ f_name(Mod),
+ f_id(ParseD),
+ f_vendor_id(ParseD),
+ f_vendor_name(ParseD),
+ f_msg_name(ParseD),
+ f_msg_header(ParseD),
+ f_rec2msg(ParseD),
+ f_msg2rec(ParseD),
+ f_name2rec(ParseD),
+ f_avp_name(ParseD),
+ f_avp_arity(ParseD),
+ f_avp_header(ParseD),
+ f_avp(ParseD),
+ f_enumerated_avp(ParseD),
+ f_empty_value(ParseD),
+ f_dict(ParseD),
+ {eof, ?LINE}]],
+
+ lists:append(Forms).
+
+make_hrl_forms(ParseD) ->
{_Prefix, MsgRecs, GrpRecs, ImportedGrpRecs}
- = make_record_forms(Spec),
+ = make_record_forms(ParseD),
RecordForms = MsgRecs ++ GrpRecs ++ lists:flatmap(fun({_,Fs}) -> Fs end,
ImportedGrpRecs),
@@ -199,16 +196,16 @@ make_hrl_forms(Spec) ->
%% export_records is used by the diameter_exprecs parse transform.
[{?attribute, export_records, RecNames} | RecordForms].
-make_record_forms(Spec) ->
- Prefix = prefix(Spec),
+make_record_forms(ParseD) ->
+ Prefix = prefix(ParseD),
- MsgRecs = a_record(Prefix, fun msg_proj/1, get_value(messages, Spec)),
- GrpRecs = a_record(Prefix, fun grp_proj/1, get_value(grouped, Spec)),
+ MsgRecs = a_record(Prefix, fun msg_proj/1, get_value(messages, ParseD)),
+ GrpRecs = a_record(Prefix, fun grp_proj/1, get_value(grouped, ParseD)),
ImportedGrpRecs = [{M, a_record(Prefix, fun grp_proj/1, Gs)}
- || {M,Gs} <- get_value(import_groups, Spec)],
+ || {M,Gs} <- get_value(import_groups, ParseD)],
- {Prefix, MsgRecs, GrpRecs, ImportedGrpRecs}.
+ {to_upper(Prefix), MsgRecs, GrpRecs, ImportedGrpRecs}.
msg_proj({Name, _, _, _, Avps}) ->
{Name, Avps}.
@@ -246,9 +243,9 @@ f_name(Name) ->
%%% # id/0
%%% ------------------------------------------------------------------------
-f_id(Spec) ->
+f_id(ParseD) ->
{?function, id, 0,
- [c_id(orddict:find(id, Spec))]}.
+ [c_id(orddict:find(id, ParseD))]}.
c_id({ok, Id}) ->
{?clause, [], [], [?INTEGER(Id)]};
@@ -260,9 +257,9 @@ c_id(error) ->
%%% # vendor_id/0
%%% ------------------------------------------------------------------------
-f_vendor_id(Spec) ->
+f_vendor_id(ParseD) ->
{?function, vendor_id, 0,
- [{?clause, [], [], [b_vendor_id(orddict:find(vendor, Spec))]}]}.
+ [{?clause, [], [], [b_vendor_id(orddict:find(vendor, ParseD))]}]}.
b_vendor_id({ok, {Id, _}}) ->
?INTEGER(Id);
@@ -273,9 +270,9 @@ b_vendor_id(error) ->
%%% # vendor_name/0
%%% ------------------------------------------------------------------------
-f_vendor_name(Spec) ->
+f_vendor_name(ParseD) ->
{?function, vendor_name, 0,
- [{?clause, [], [], [b_vendor_name(orddict:find(vendor, Spec))]}]}.
+ [{?clause, [], [], [b_vendor_name(orddict:find(vendor, ParseD))]}]}.
b_vendor_name({ok, {_, Name}}) ->
?Atom(Name);
@@ -286,15 +283,15 @@ b_vendor_name(error) ->
%%% # msg_name/1
%%% ------------------------------------------------------------------------
-f_msg_name(Spec) ->
- {?function, msg_name, 2, msg_name(Spec)}.
+f_msg_name(ParseD) ->
+ {?function, msg_name, 2, msg_name(ParseD)}.
%% Return the empty name for any unknown command to which
%% DIAMETER_COMMAND_UNSUPPORTED should be replied.
-msg_name(Spec) ->
+msg_name(ParseD) ->
lists:flatmap(fun c_msg_name/1, proplists:get_value(command_codes,
- Spec,
+ ParseD,
[]))
++ [{?clause, [?VAR('_'), ?VAR('_')], [], [?ATOM('')]}].
@@ -310,12 +307,12 @@ c_msg_name({Code, Req, Ans}) ->
%%% # msg2rec/1
%%% ------------------------------------------------------------------------
-f_msg2rec(Spec) ->
- {?function, msg2rec, 1, msg2rec(Spec)}.
+f_msg2rec(ParseD) ->
+ {?function, msg2rec, 1, msg2rec(ParseD)}.
-msg2rec(Spec) ->
- Pre = prefix(Spec),
- lists:map(fun(T) -> c_msg2rec(T, Pre) end, get_value(messages, Spec))
+msg2rec(ParseD) ->
+ Pre = prefix(ParseD),
+ lists:map(fun(T) -> c_msg2rec(T, Pre) end, get_value(messages, ParseD))
++ [?BADARG(1)].
c_msg2rec({N,_,_,_,_}, Pre) ->
@@ -325,12 +322,12 @@ c_msg2rec({N,_,_,_,_}, Pre) ->
%%% # rec2msg/1
%%% ------------------------------------------------------------------------
-f_rec2msg(Spec) ->
- {?function, rec2msg, 1, rec2msg(Spec)}.
+f_rec2msg(ParseD) ->
+ {?function, rec2msg, 1, rec2msg(ParseD)}.
-rec2msg(Spec) ->
- Pre = prefix(Spec),
- lists:map(fun(T) -> c_rec2msg(T, Pre) end, get_value(messages, Spec))
+rec2msg(ParseD) ->
+ Pre = prefix(ParseD),
+ lists:map(fun(T) -> c_rec2msg(T, Pre) end, get_value(messages, ParseD))
++ [?BADARG(1)].
c_rec2msg({N,_,_,_,_}, Pre) ->
@@ -340,13 +337,13 @@ c_rec2msg({N,_,_,_,_}, Pre) ->
%%% # name2rec/1
%%% ------------------------------------------------------------------------
-f_name2rec(Spec) ->
- {?function, name2rec, 1, name2rec(Spec)}.
+f_name2rec(ParseD) ->
+ {?function, name2rec, 1, name2rec(ParseD)}.
-name2rec(Spec) ->
- Pre = prefix(Spec),
- Groups = get_value(grouped, Spec)
- ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)),
+name2rec(ParseD) ->
+ Pre = prefix(ParseD),
+ Groups = get_value(grouped, ParseD)
+ ++ lists:flatmap(fun avps/1, get_value(import_groups, ParseD)),
lists:map(fun({N,_,_,_}) -> c_name2rec(N, Pre) end, Groups)
++ [{?clause, [?VAR('T')], [], [?CALL(msg2rec, [?VAR('T')])]}].
@@ -360,8 +357,8 @@ avps({_Mod, Avps}) ->
%%% # avp_name/1
%%% ------------------------------------------------------------------------
-f_avp_name(Spec) ->
- {?function, avp_name, 2, avp_name(Spec)}.
+f_avp_name(ParseD) ->
+ {?function, avp_name, 2, avp_name(ParseD)}.
%% 3588, 4.1:
%%
@@ -372,11 +369,11 @@ f_avp_name(Spec) ->
%% field. AVP numbers 256 and above are used for Diameter, which are
%% allocated by IANA (see Section 11.1).
-avp_name(Spec) ->
- Avps = get_value(avp_types, Spec),
- Imported = get_value(import_avps, Spec),
- Vid = orddict:find(vendor, Spec),
- Vs = vendor_id_map(Spec),
+avp_name(ParseD) ->
+ Avps = get_value(avp_types, ParseD),
+ Imported = get_value(import_avps, ParseD),
+ Vid = orddict:find(vendor, ParseD),
+ Vs = vendor_id_map(ParseD),
lists:map(fun(T) -> c_avp_name(T, Vs, Vid) end, Avps)
++ lists:flatmap(fun(T) -> c_imported_avp_name(T, Vs) end, Imported)
@@ -407,25 +404,25 @@ c_avp_name_(T, Code, Vid) ->
[],
[T]}.
-vendor_id_map(Spec) ->
+vendor_id_map(ParseD) ->
lists:flatmap(fun({V,Ns}) -> [{N,V} || N <- Ns] end,
- get_value(avp_vendor_id, Spec))
+ get_value(avp_vendor_id, ParseD))
++ lists:flatmap(fun({_,_,[],_}) -> [];
({N,_,[V],_}) -> [{N,V}]
end,
- get_value(grouped, Spec)).
+ get_value(grouped, ParseD)).
%%% ------------------------------------------------------------------------
%%% # avp_arity/2
%%% ------------------------------------------------------------------------
-f_avp_arity(Spec) ->
- {?function, avp_arity, 2, avp_arity(Spec)}.
+f_avp_arity(ParseD) ->
+ {?function, avp_arity, 2, avp_arity(ParseD)}.
-avp_arity(Spec) ->
- Msgs = get_value(messages, Spec),
- Groups = get_value(grouped, Spec)
- ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)),
+avp_arity(ParseD) ->
+ Msgs = get_value(messages, ParseD),
+ Groups = get_value(grouped, ParseD)
+ ++ lists:flatmap(fun avps/1, get_value(import_groups, ParseD)),
c_avp_arity(Msgs ++ Groups)
++ [{?clause, [?VAR('_'), ?VAR('_')], [], [?INTEGER(0)]}].
@@ -449,15 +446,15 @@ c_arity(Name, Avp) ->
%%% # avp/3
%%% ------------------------------------------------------------------------
-f_avp(Spec) ->
- {?function, avp, 3, avp(Spec) ++ [?BADARG(3)]}.
+f_avp(ParseD) ->
+ {?function, avp, 3, avp(ParseD) ++ [?BADARG(3)]}.
-avp(Spec) ->
- Native = get_value(avp_types, Spec),
- CustomMods = get_value(custom_types, Spec),
- TypeMods = get_value(codecs, Spec),
- Imported = get_value(import_avps, Spec),
- Enums = get_value(enum, Spec),
+avp(ParseD) ->
+ Native = get_value(avp_types, ParseD),
+ CustomMods = get_value(custom_types, ParseD),
+ TypeMods = get_value(codecs, ParseD),
+ Imported = get_value(import_avps, ParseD),
+ Enums = get_value(enum, ParseD),
Custom = lists:map(fun({M,As}) -> {M, custom_types, As} end,
CustomMods)
@@ -548,14 +545,14 @@ custom(codecs, AvpName, Type) ->
%%% # enumerated_avp/3
%%% ------------------------------------------------------------------------
-f_enumerated_avp(Spec) ->
- {?function, enumerated_avp, 3, enumerated_avp(Spec) ++ [?BADARG(3)]}.
+f_enumerated_avp(ParseD) ->
+ {?function, enumerated_avp, 3, enumerated_avp(ParseD) ++ [?BADARG(3)]}.
-enumerated_avp(Spec) ->
- Enums = get_value(enum, Spec),
+enumerated_avp(ParseD) ->
+ Enums = get_value(enum, ParseD),
lists:flatmap(fun cs_enumerated_avp/1, Enums)
++ lists:flatmap(fun({M,Es}) -> enumerated_avp(M, Es, Enums) end,
- get_value(import_enums, Spec)).
+ get_value(import_enums, ParseD)).
enumerated_avp(Mod, Es, Enums) ->
lists:flatmap(fun({N,_}) ->
@@ -585,16 +582,16 @@ c_enumerated_avp(AvpName, {_,I}) ->
%%% msg_header/1
%%% ------------------------------------------------------------------------
-f_msg_header(Spec) ->
- {?function, msg_header, 1, msg_header(Spec) ++ [?BADARG(1)]}.
+f_msg_header(ParseD) ->
+ {?function, msg_header, 1, msg_header(ParseD) ++ [?BADARG(1)]}.
-msg_header(Spec) ->
- msg_header(get_value(messages, Spec), Spec).
+msg_header(ParseD) ->
+ msg_header(get_value(messages, ParseD), ParseD).
msg_header([], _) ->
[];
-msg_header(Msgs, Spec) ->
- ApplId = orddict:fetch(id, Spec),
+msg_header(Msgs, ParseD) ->
+ ApplId = orddict:fetch(id, ParseD),
lists:map(fun({M,C,F,_,_}) -> c_msg_header(M, C, F, ApplId) end, Msgs).
@@ -616,14 +613,14 @@ emf('ERR', N) -> N bor 2#00100000.
%%% # avp_header/1
%%% ------------------------------------------------------------------------
-f_avp_header(Spec) ->
- {?function, avp_header, 1, avp_header(Spec) ++ [?BADARG(1)]}.
+f_avp_header(ParseD) ->
+ {?function, avp_header, 1, avp_header(ParseD) ++ [?BADARG(1)]}.
-avp_header(Spec) ->
- Native = get_value(avp_types, Spec),
- Imported = get_value(import_avps, Spec),
- Vid = orddict:find(vendor, Spec),
- Vs = vendor_id_map(Spec),
+avp_header(ParseD) ->
+ Native = get_value(avp_types, ParseD),
+ Imported = get_value(import_avps, ParseD),
+ Vid = orddict:find(vendor, ParseD),
+ Vs = vendor_id_map(ParseD),
lists:flatmap(fun(A) -> c_avp_header(A, Vs, Vid) end,
Native ++ Imported).
@@ -679,14 +676,14 @@ v(false, _, _, _) ->
%%% # empty_value/0
%%% ------------------------------------------------------------------------
-f_empty_value(Spec) ->
- {?function, empty_value, 1, empty_value(Spec)}.
+f_empty_value(ParseD) ->
+ {?function, empty_value, 1, empty_value(ParseD)}.
-empty_value(Spec) ->
- Imported = lists:flatmap(fun avps/1, get_value(import_enums, Spec)),
- Groups = get_value(grouped, Spec)
- ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)),
- Enums = [T || {N,_} = T <- get_value(enum, Spec),
+empty_value(ParseD) ->
+ Imported = lists:flatmap(fun avps/1, get_value(import_enums, ParseD)),
+ Groups = get_value(grouped, ParseD)
+ ++ lists:flatmap(fun avps/1, get_value(import_groups, ParseD)),
+ Enums = [T || {N,_} = T <- get_value(enum, ParseD),
not lists:keymember(N, 1, Imported)]
++ Imported,
lists:map(fun c_empty_value/1, Groups ++ Enums)
@@ -706,72 +703,52 @@ c_empty_value({Name, _}) ->
%%% # dict/0
%%% ------------------------------------------------------------------------
-f_dict(Spec) ->
+f_dict(ParseD) ->
{?function, dict, 0,
- [{?clause, [], [], [?TERM([?VERSION | Spec])]}]}.
+ [{?clause, [], [], [?TERM([?VERSION | ParseD])]}]}.
%%% ------------------------------------------------------------------------
-%%% # gen_hrl/3
+%%% # gen_hrl/2
%%% ------------------------------------------------------------------------
-gen_hrl(Path, Mod, Spec) ->
- {ok, Fd} = file:open(Path, [write]),
-
+gen_hrl(Mod, ParseD) ->
{Prefix, MsgRecs, GrpRecs, ImportedGrpRecs}
- = make_record_forms(Spec),
-
- file:write(Fd, hrl_header(Mod)),
-
- forms("Message records", Fd, MsgRecs),
- forms("Grouped AVP records", Fd, GrpRecs),
-
- lists:foreach(fun({M,Fs}) ->
- forms("Grouped AVP records from " ++ atom_to_list(M),
- Fd,
- Fs)
- end,
- ImportedGrpRecs),
-
- PREFIX = to_upper(Prefix),
-
- write("ENUM Macros",
- Fd,
- m_enums(PREFIX, false, get_value(enum, Spec))),
- write("DEFINE Macros",
- Fd,
- m_enums(PREFIX, false, get_value(define, Spec))),
-
- lists:foreach(fun({M,Es}) ->
- write("ENUM Macros from " ++ atom_to_list(M),
- Fd,
- m_enums(PREFIX, true, Es))
- end,
- get_value(import_enums, Spec)),
-
- file:close(Fd).
-
-forms(_, _, []) ->
- ok;
-forms(Banner, Fd, Forms) ->
- write(Banner, Fd, prettypr(Forms)).
-
-write(_, _, []) ->
- ok;
-write(Banner, Fd, Str) ->
- banner(Fd, Banner),
- io:fwrite(Fd, "~s~n", [Str]).
+ = make_record_forms(ParseD),
+
+ [hrl_header(Mod),
+ forms("Message records", MsgRecs),
+ forms("Grouped AVP records", GrpRecs),
+ lists:map(fun({M,Fs}) ->
+ forms("Grouped AVP records from " ++ atom_to_list(M),
+ Fs)
+ end,
+ ImportedGrpRecs),
+ format("ENUM Macros", m_enums(Prefix, false, get_value(enum, ParseD))),
+ format("DEFINE Macros", m_enums(Prefix, false, get_value(define, ParseD))),
+ lists:map(fun({M,Es}) ->
+ format("ENUM Macros from " ++ atom_to_list(M),
+ m_enums(Prefix, true, Es))
+ end,
+ get_value(import_enums, ParseD))].
+
+forms(_, [] = No) ->
+ No;
+forms(Banner, Forms) ->
+ format(Banner, prettypr(Forms)).
+
+format(_, [] = No) ->
+ No;
+format(Banner, Str) ->
+ [banner(Banner), Str, $\n].
prettypr(Forms) ->
erl_prettypr:format(erl_syntax:form_list(Forms)).
-banner(Fd, Heading) ->
- file:write(Fd, banner(Heading)).
-
banner(Heading) ->
- ("\n\n"
+ ["\n\n"
"%%% -------------------------------------------------------\n"
- "%%% " ++ Heading ++ ":\n"
- "%%% -------------------------------------------------------\n\n").
+ "%%% ", Heading, ":\n"
+ "%%% -------------------------------------------------------\n\n"].
z(S) ->
string:join(string:tokens(S, "\s\t"), "\s").
@@ -845,8 +822,8 @@ arity([_], '*' = Inf) -> {0, Inf};
arity({_}, '*' = Inf) -> {1, Inf};
arity(_, {_,_} = Q) -> Q.
-prefix(Spec) ->
- case orddict:find(prefix, Spec) of
+prefix(ParseD) ->
+ case orddict:find(prefix, ParseD) of
{ok, P} ->
P ++ "_";
error ->
@@ -855,3 +832,70 @@ prefix(Spec) ->
rec_name(Name, Prefix) ->
Prefix ++ Name.
+
+%% ===========================================================================
+%% pp/1
+%%
+%% Preprocess forms as generated by 'forms' option. In particular,
+%% replace the include_lib attributes in generated forms by the
+%% corresponding forms, extracting the latter from an existing
+%% dictionary (diameter_gen_relay). The resulting forms can be
+%% compiled to beam using compile:forms/2 (which does no preprocessing
+%% or it's own; DiY currently appears to be the only way to preprocess
+%% a forms list).
+
+pp(Forms) ->
+ {_, Beam, _} = code:get_object_code(diameter_gen_relay),
+ pp(Forms, abstract_code(Beam)).
+
+pp(Forms, {ok, Code}) ->
+ Files = files(Code, []),
+ lists:flatmap(fun(T) -> include(T, Files) end, Forms);
+
+pp(Forms, {error, Reason}) ->
+ erlang:error({forms, Reason, Forms}).
+
+include({attribute, _, include_lib, Path}, Files) ->
+ Inc = filename:basename(Path),
+ [{Inc, Forms}] = [T || {F, _} = T <- Files, F == Inc], %% expect one
+ lists:flatmap(fun filter/1, Forms);
+
+include(T, _) ->
+ [T].
+
+abstract_code(Beam) ->
+ case beam_lib:chunks(Beam, [abstract_code]) of
+ {ok, {_Mod, [{abstract_code, {_Vsn, Code}}]}} ->
+ {ok, Code};
+ {ok, {_Mod, [{abstract_code, no_abstract_code = No}]}} ->
+ {error, No};
+ {error = E, beam_lib, Reason} ->
+ {E, Reason}
+ end.
+
+files([{attribute, _, file, {Path, _}} | T], Acc) ->
+ {Body, Rest} = lists:splitwith(fun({attribute, _, file, _}) -> false;
+ (_) -> true
+ end,
+ T),
+ files(Rest, [{filename:basename(Path), Body} | Acc]);
+
+files([], Acc) ->
+ Acc.
+
+%% Only retain record diameter_avp and functions not generated by
+%% diameter_exprecs.
+
+filter({attribute, _, record, {diameter_avp, _}} = T) ->
+ [T];
+
+filter({function, _, Name, _, _} = T) ->
+ case ?S(Name) of
+ [$#|_] -> %% generated by diameter_exprecs
+ [];
+ _ ->
+ [T]
+ end;
+
+filter(_) ->
+ [].
diff --git a/lib/diameter/src/compiler/diameter_dict_util.erl b/lib/diameter/src/compiler/diameter_dict_util.erl
index 36a6efa294..3941f30e03 100644
--- a/lib/diameter/src/compiler/diameter_dict_util.erl
+++ b/lib/diameter/src/compiler/diameter_dict_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -46,7 +46,7 @@
-spec parse(File, Opts)
-> {ok, orddict:orddict()}
| {error, term()}
- when File :: {path, string()}
+ when File :: {path, file:name_all()}
| iolist()
| binary(),
Opts :: list().
@@ -265,6 +265,9 @@ io(K, Id)
io(vendor = K, {Id, Name}) ->
[?NL, section(K) | [[?SP, tok(X)] || X <- [Id, Name]]];
+io(_, []) ->
+ [];
+
io(avp_types = K, Body) ->
[?NL, ?NL, section(K), ?NL, [body(K,A) || A <- Body]];
diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl
index 16e30c1ffb..2f314b7e57 100644
--- a/lib/diameter/src/compiler/diameter_make.erl
+++ b/lib/diameter/src/compiler/diameter_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,102 +30,231 @@
-module(diameter_make).
--export([codec/1,
- codec/2,
- dict/1,
- dict/2,
+-export([codec/2,
+ codec/1,
format/1,
- reformat/1]).
+ flatten/1]).
-export_type([opt/0]).
+-include("diameter_vsn.hrl").
+
+%% Options passed to codec/2.
-type opt() :: {include|outdir|name|prefix|inherits, string()}
+ | return
| verbose
- | debug.
+ | parse %% internal parsed form
+ | forms %% abstract format for compile:forms/1,2
+ | erl
+ | hrl.
+
+%% Internal parsed format with a version tag.
+-type parsed() :: list().
+
+%% Literal dictionary or path. A NL of CR identifies the former.
+-type dict() :: iolist()
+ | binary()
+ | parsed(). %% as returned by codec/2
+
+%% Name of a literal dictionary if otherwise unspecified.
+-define(DEFAULT_DICT_FILE, "dictionary.dia").
%% ===========================================================================
%% codec/1-2
%%
-%% Parse a dictionary file and generate a codec module.
+%% Parse a dictionary file and generate a codec module. Input
+%% dictionary can be either a path or the dictionary itself: the
+%% occurrence of \n or \r in the argument is used to distinguish the
+%% two.
--spec codec(Path, [opt()])
+-spec codec(File, [opt()])
-> ok
+ | {ok, list()} %% with option 'return', one element for each output
| {error, Reason}
- when Path :: string(),
+ when File :: dict()
+ | {path, file:name_all()},
Reason :: string().
codec(File, Opts) ->
- case dict(File, Opts) of
- {ok, Dict} ->
- make(File,
- Opts,
- Dict,
- [spec || _ <- [1], lists:member(debug, Opts)] ++ [erl, hrl]);
- {error, _} = E ->
- E
+ {Dict, Path} = identify(File),
+ case parse(Dict, Opts) of
+ {ok, ParseD} ->
+ make(Path, default(Opts), ParseD);
+ {error = E, Reason} ->
+ {E, diameter_dict_util:format_error(Reason)}
end.
codec(File) ->
codec(File, []).
-%% dict/2
+%% format/1
%%
-%% Parse a dictionary file and return the orddict that a codec module
-%% returns from dict/0.
-
--spec dict(string(), [opt()])
- -> {ok, orddict:orddict()}
- | {error, string()}.
+%% Turn an orddict returned by dict/1-2 back into a dictionary.
-dict(Path, Opts) ->
- case diameter_dict_util:parse({path, Path}, Opts) of
- {ok, _} = Ok ->
- Ok;
- {error = E, Reason} ->
- {E, diameter_dict_util:format_error(Reason)}
- end.
+-spec format(parsed())
+ -> iolist().
-dict(File) ->
- dict(File, []).
+format([?VERSION | Dict]) ->
+ diameter_dict_util:format(Dict).
-%% format/1
+%% flatten/1
%%
-%% Turn an orddict returned by dict/1-2 back into a dictionary file
-%% in the form of an iolist().
+%% Reconstitute a dictionary without @inherits.
--spec format(orddict:orddict())
- -> iolist().
+-spec flatten(parsed())
+ -> parsed().
-format(Dict) ->
- diameter_dict_util:format(Dict).
+flatten([?VERSION = V | Dict]) ->
+ [V | lists:foldl(fun flatten/2,
+ Dict,
+ [avp_vendor_id,
+ custom_types,
+ codecs,
+ [avp_types, import_avps],
+ [grouped, import_groups],
+ [enum, import_enums]])].
+
+%% ===========================================================================
+
+%% flatten/2
+
+flatten([_,_] = Keys, Dict) ->
+ [Values, Imports] = [orddict:fetch(K, Dict) || K <- Keys],
+ Vs = lists:append([Values | [V || {_Mod, V} <- Imports]]),
+ lists:foldl(fun({K,V},D) -> orddict:store(K,V,D) end,
+ Dict,
+ lists:zip([inherits | Keys], [[], Vs, []]));
+
+%% Inherited avp's setting the 'V' flag get their value either from
+%% @avp_vendor_id in the inheriting dictionary or from @vendor in the
+%% *inherited* (not inheriting) dictionary: add the latter to
+%% @avp_vendor_id as required.
+flatten(avp_vendor_id = Key, Dict) ->
+ Def = orddict:find(vendor, Dict),
+ ModD = imports(Dict),
+ Vids = orddict:fetch(Key, Dict),
+ Avps = lists:append([As || {_,As} <- Vids]),
+ orddict:store(Key,
+ dict:fold(fun(M, As, A) -> vid(M, As -- Avps, Def, A) end,
+ Vids,
+ ModD),
+ Dict);
+
+%% Import @codecs and @custom_types from inherited dictionaries as
+%% required.
+flatten(Key, Dict) ->
+ ImportAvps = orddict:fetch(import_avps, Dict),
+ ImportItems = [{M, As}
+ || {Mod, Avps} <- ImportAvps,
+ [_|D] <- [Mod:dict()],
+ {M,As0} <- orddict:fetch(Key, D),
+ F <- [fun(A) -> lists:keymember(A, 1, Avps) end],
+ [_|_] = As <- [lists:filter(F, As0)]],
+ orddict:store(Key,
+ lists:foldl(fun merge/2,
+ orddict:fetch(Key, Dict),
+ ImportItems),
+ Dict).
-%% reformat/1
+%% merge/2
+
+merge({Mod, _Avps} = T, Acc) ->
+ merge(lists:keyfind(Mod, 1, Acc), T, Acc).
+
+merge({Mod, Avps}, {Mod, As}, Acc) ->
+ lists:keyreplace(Mod, 1, Acc, {Mod, Avps ++ As});
+merge(false, T, Acc) ->
+ [T | Acc].
+
+%% imports/1
%%
-%% Parse a dictionary file and return its formatted equivalent.
+%% Return a module() -> [AVP] dict of inherited AVP's setting the V flag.
--spec reformat(File)
- -> {ok, iolist()}
- | {error, Reason}
- when File :: string(),
- Reason :: string().
+imports(Dict) ->
+ lists:foldl(fun imports/2,
+ dict:new(),
+ orddict:fetch(import_avps, Dict)).
+
+imports({Mod, Avps}, Dict) ->
+ dict:store(Mod,
+ [A || {A,_,_,Fs} <- Avps, lists:member($V, Fs)],
+ Dict).
-reformat(File) ->
- case dict(File) of
- {ok, Dict} ->
- {ok, format(Dict)};
- {error, _} = No ->
- No
+%% vid/4
+
+vid(_, [], _, Acc) ->
+ Acc;
+vid(Mod, Avps, Def, Acc) ->
+ v(Mod:vendor_id(), Avps, Def, Acc).
+
+v(Vid, _, {ok, {Vid, _}}, Acc) -> %% same id as inheriting dictionary's
+ Acc;
+v(Vid, Avps, _, Acc) ->
+ case lists:keyfind(Vid, 1, Acc) of
+ {Vid, As} ->
+ lists:keyreplace(Vid, 1, Acc, {Vid, As ++ Avps});
+ false ->
+ [{Vid, Avps} | Acc]
end.
%% ===========================================================================
-make(_, _, _, []) ->
+parse({dict, ParseD}, _) ->
+ {ok, ParseD};
+parse(File, Opts) ->
+ diameter_dict_util:parse(File, Opts).
+
+default(Opts) ->
+ def(modes(Opts), Opts).
+
+def([], Opts) ->
+ [erl, hrl | Opts];
+def(_, Opts) ->
+ Opts.
+
+modes(Opts) ->
+ lists:filter(fun is_mode/1, Opts).
+
+is_mode(T) ->
+ lists:member(T, [erl, hrl, parse, forms]).
+
+identify([Vsn | [T|_] = ParseD])
+ when is_tuple(T) ->
+ ?VERSION == Vsn orelse erlang:error({version, {Vsn, ?VERSION}}),
+ {{dict, ParseD}, ?DEFAULT_DICT_FILE};
+identify({path, File} = T) ->
+ {T, File};
+identify(File) ->
+ Bin = iolist_to_binary([File]),
+ case is_path(Bin) of
+ true -> {{path, File}, File};
+ false -> {Bin, ?DEFAULT_DICT_FILE}
+ end.
+
+%% Interpret anything containing \n or \r as a literal dictionary,
+%% otherwise a path. (Which might be the wrong guess in the worst case.)
+is_path(Bin) ->
+ try
+ [throw(C) || <<C>> <= Bin, $\n == C orelse $\r == C],
+ true
+ catch
+ throw:_ -> false
+ end.
+
+make(File, Opts, Dict) ->
+ ok(lists:foldl(fun(M,A) -> [make(File, Opts, Dict, M) | A] end,
+ [],
+ modes(Opts))).
+
+ok([ok|_]) ->
ok;
-make(File, Opts, Dict, [Mode | Rest]) ->
+ok([_|_] = L) ->
+ {ok, lists:reverse(L)}.
+
+make(File, Opts, Dict, Mode) ->
try
- ok = diameter_codegen:from_dict(File, Dict, Opts, Mode),
- make(File, Opts, Dict, Rest)
+ diameter_codegen:from_dict(File, Dict, Opts, Mode)
catch
error: Reason ->
erlang:error({Reason, Mode, erlang:get_stacktrace()})
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index 76fb54e03a..c7ae8a2828 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -31,14 +31,26 @@
{"1.4", [{restart_application, diameter}]}, %% R16A
{"1.4.1", [{restart_application, diameter}]}, %% R16B
{"1.4.1.1", [{restart_application, diameter}]},
- {"1.4.2", [{load_module, diameter_types}, %% R16B01
+ {"1.4.2", [{load_module, diameter_codec}, %% R16B01
+ {load_module, diameter_types},
{load_module, diameter_config},
+ {load_module, diameter_capx},
{load_module, diameter_service},
{load_module, diameter_peer_fsm},
- {load_module, diameter_watchdog}]},
- {"1.4.3", [{load_module, diameter_watchdog}, %% R16B02
+ {load_module, diameter_watchdog},
+ {load_module, diameter}]},
+ {"1.4.3", [{load_module, diameter_capx}, %% R16B02
+ {load_module, diameter_service},
+ {load_module, diameter_watchdog},
{load_module, diameter_codec},
- {load_module, diameter_types}]}
+ {load_module, diameter_types},
+ {load_module, diameter_config},
+ {load_module, diameter}]},
+ {"1.4.4", [{load_module, diameter_capx},
+ {load_module, diameter_service},
+ {load_module, diameter_watchdog},
+ {load_module, diameter_config},
+ {load_module, diameter}]}
],
[
{"0.9", [{restart_application, diameter}]},
@@ -54,7 +66,16 @@
{"1.4.1.1", [{restart_application, diameter}]},
{"1.4.2", [{restart_application, diameter}]},
{"1.4.3", [{load_module, diameter_types},
+ {load_module, diameter_config},
{load_module, diameter_codec},
- {load_module, diameter_watchdog}]}
+ {load_module, diameter_service},
+ {load_module, diameter_watchdog},
+ {load_module, diameter_capx},
+ {load_module, diameter}]},
+ {"1.4.4", [{load_module, diameter_capx},
+ {load_module, diameter_config},
+ {load_module, diameter_service},
+ {load_module, diameter_watchdog},
+ {load_module, diameter}]}
]
}.
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index 295d23912b..0b4568a9e5 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -473,9 +473,6 @@ pack(true, Arity, Avp, Value, Acc) ->
pack(false, Arity, Avp, Value, Acc) ->
min(Arity, Avp, Value, Acc).
-all(Mod, Name, Avp, V) ->
- all(Mod:avp_arity(Name, Avp), Avp, V).
-
all(1, Avp, V) ->
{Avp, V};
all({0,'*'}, Avp, V) ->
@@ -489,9 +486,6 @@ a(N, Avp, V)
when N /= 0 ->
{Avp, lists:duplicate(N,V)}.
-min(Mod, Name, Avp, V, Acc) ->
- min(Mod:avp_arity(Name, Avp), Avp, V, Acc).
-
min(1, Avp, V, Acc) ->
[{Avp, V} | Acc];
min({0,_}, _, _, Acc) ->
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index 81722c8dca..ed369e8af3 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -31,10 +31,15 @@
%% testcases
-export([format/1, format/2,
replace/1, replace/2,
- generate/1, generate/4]).
+ generate/1, generate/4,
+ flatten1/1, flatten1/3,
+ flatten2/1]).
-export([dict/0]). %% fake dictionary module
+%% dictionary callbacks for flatten2/1
+-export(['A1'/3, 'Unsigned32'/3]).
+
-define(base, "base_rfc3588.dia").
-define(util, diameter_util).
-define(S, atom_to_list).
@@ -45,7 +50,7 @@
%% RE/Replacement (in the sense of re:replace/4) pairs for morphing
%% base_rfc3588.dia. The key is 'ok' or the the expected error as
%% returned in the first element of the error tuple returned by
-%% diameter_dict_util:parse/2.
+%% diameter_make:codec/2.
-define(REPLACE,
[{ok,
"",
@@ -335,7 +340,9 @@ suite() ->
all() ->
[format,
replace,
- generate].
+ generate,
+ flatten1,
+ flatten2].
%% Error handling testcases will make an erroneous dictionary out of
%% the base dictionary and check that the expected error results.
@@ -361,10 +368,18 @@ format(Config) ->
format(Mods, Bin) ->
B = modify(Bin, Mods),
- {ok, Dict} = diameter_dict_util:parse(B, []),
- {ok, D} = diameter_dict_util:parse(diameter_dict_util:format(Dict), []),
+ {ok, Dict} = parse(B, []),
+ {ok, D} = parse(diameter_make:format(Dict), []),
{Dict, Dict} = {Dict, D}.
+parse(File, Opts) ->
+ case diameter_make:codec(File, [parse, hrl, return | Opts]) of
+ {ok, [Dict, _]} ->
+ {ok, Dict};
+ {error, _} = E ->
+ E
+ end.
+
%% ===========================================================================
%% replace/1
%%
@@ -379,13 +394,10 @@ replace(Config) ->
replace({E, Mods}, Bin) ->
B = modify(Bin, Mods),
- case {E, diameter_dict_util:parse(B, [{include, here()}]), Mods} of
+ case {E, parse(B, [{include, here()}]), Mods} of
{ok, {ok, Dict}, _} ->
Dict;
- {_, {error, {E,_} = T}, _} ->
- S = diameter_dict_util:format_error(T),
- true = nochar($", S, E),
- true = nochar($', S, E),
+ {_, {error, S}, _} ->
S
end.
@@ -403,20 +415,127 @@ generate(Config) ->
[] = ?util:run([{?MODULE, [generate, M, Bin, N, T]}
|| {E,N} <- Rs,
{ok, M} <- [norm(E)],
- T <- [erl, hrl, spec]]).
+ T <- [erl, hrl, parse, forms]]).
generate(Mods, Bin, N, Mode) ->
B = modify(Bin, Mods ++ [{"@name .*", "@name dict" ++ ?L(N)}]),
- {ok, Dict} = diameter_dict_util:parse(B, []),
+ {ok, Dict} = parse(B, []),
File = "dict" ++ integer_to_list(N),
- {_, ok} = {Dict, diameter_codegen:from_dict("dict",
- Dict,
- [{name, File},
- {prefix, "base"},
- debug],
- Mode)},
- Mode == erl
- andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])).
+ {_, ok} = {Dict, diameter_make:codec(Dict,
+ [{name, File},
+ {prefix, "base"},
+ Mode])},
+ generate(Mode, File, Dict).
+
+generate(erl, File, _) ->
+ {ok, _} = compile:file(File ++ ".erl", [return_errors]);
+
+generate(forms, File, _) ->
+ {ok, [_]} = file:consult(File ++ ".F");
+
+generate(parse, File, Dict) ->
+ {ok, [Dict]} = file:consult(File ++ ".D"), %% assert
+ {ok, [F]} = diameter_make:codec(Dict, [forms, return]),
+ {ok, _, _, _} = compile:forms(F, [return]);
+
+generate(hrl, _, _) ->
+ ok.
+
+%% ===========================================================================
+%% flatten1/1
+
+flatten1(_Config) ->
+ [Vsn | BaseD] = diameter_gen_base_rfc6733:dict(),
+ {ok, I} = parse("@inherits diameter_gen_base_rfc6733\n", []),
+ [Vsn | FlatD] = diameter_make:flatten(I),
+ [] = ?util:run([{?MODULE, [flatten1, K, BaseD, FlatD]}
+ || K <- [avp_types, grouped, enum]]).
+
+flatten1(Key, BaseD, FlatD) ->
+ Vs = orddict:fetch(Key, BaseD),
+ Vs = orddict:fetch(Key, FlatD).
+
+%% ===========================================================================
+%% flatten2/1
+
+flatten2(_Config) ->
+ Dict1 =
+ "@name diameter_test1\n"
+ "@prefix diameter_test1\n"
+ "@vendor 666 test\n"
+ "@avp_vendor_id 111 A1 A3\n"
+ "@avp_vendor_id 222 A4 A6\n"
+ "@custom_types " ++ ?S(?MODULE) ++ " A1 A4\n"
+ "@codecs " ++ ?S(?MODULE) ++ " A3 A6\n"
+ "@avp_types\n"
+ "A1 1001 Unsigned32 V\n"
+ "A2 1002 Unsigned32 V\n"
+ "A3 1003 Unsigned32 V\n"
+ "A4 1004 Unsigned32 V\n"
+ "A5 1005 Unsigned32 V\n"
+ "A6 1006 Unsigned32 V\n"
+ "@end ignored\n",
+ Dict2 =
+ "@name diameter_test2\n"
+ "@prefix diameter_test2\n"
+ "@vendor 777 test\n"
+ "@inherits diameter_test1 A1 A2 A3\n"
+ "@inherits diameter_gen_base_rfc6733\n"
+ "@avp_vendor_id 333 A1\n",
+
+ {ok, [E1, F1]}
+ = diameter_make:codec(Dict1, [erl, forms, return]),
+ ct:pal("~s", [E1]),
+ diameter_test1 = M1 = load_forms(F1),
+
+ {ok, [D2, E2, F2]}
+ = diameter_make:codec(Dict2, [parse, erl, forms, return]),
+ ct:pal("~s", [E2]),
+ diameter_test2 = M2 = load_forms(F2),
+
+ Flat = lists:flatten(diameter_make:format(diameter_make:flatten(D2))),
+ ct:pal("~s", [Flat]),
+ {ok, [E3, F3]}
+ = diameter_make:codec(Flat, [erl, forms, return,
+ {name, "diameter_test3"}]),
+ ct:pal("~s", [E3]),
+ diameter_test3 = M3 = load_forms(F3),
+
+ [{1001, 111, M1, 'A1'}, %% @avp_vendor_id
+ {1002, 666, M1, 'A2'}, %% @vendor
+ {1003, 111, M1, 'A3'}, %% @avp_vendor_id
+ {1004, 222, M1, 'A4'}, %% @avp_vendor_id
+ {1005, 666, M1, 'A5'}, %% @vendor
+ {1006, 222, M1, 'A6'}, %% @avp_vendor_id
+ {1001, 333, M2, 'A1'}, %% M2 @avp_vendor_id
+ {1002, 666, M2, 'A2'}, %% M1 @vendor
+ {1003, 666, M2, 'A3'}, %% M1 @vendor
+ {1001, 333, M3, 'A1'}, %% (as for M2)
+ {1002, 666, M3, 'A2'}, %% "
+ {1003, 666, M3, 'A3'}] %% "
+ = [{Code, Vid, Mod, Name}
+ || Mod <- [M1, M2, M3],
+ Code <- lists:seq(1001, 1006),
+ Vid <- [666, 111, 222, 777, 333],
+ {Name, 'Unsigned32'} <- [Mod:avp_name(Code, Vid)]],
+
+ [] = [{A,T,M,RC} || A <- ['A1', 'A3'],
+ T <- [encode, decode],
+ M <- [M2, M3],
+ Ref <- [make_ref()],
+ RC <- [M:avp(T, Ref, A)],
+ RC /= {T, Ref}].
+
+'A1'(T, 'Unsigned32', Ref) ->
+ {T, Ref}.
+
+'Unsigned32'(T, 'A3', Ref) ->
+ {T, Ref}.
+
+load_forms(Forms) ->
+ {ok, Mod, Bin, _} = compile:forms(Forms, [return]),
+ {module, Mod} = code:load_binary(Mod, ?S(Mod), Bin),
+ Mod.
%% ===========================================================================
@@ -428,9 +547,6 @@ norm({E, RE, Repl}) ->
norm({_,_} = T) ->
T.
-nochar(Char, Str, Err) ->
- Err == parse orelse not lists:member(Char, Str) orelse Str.
-
here() ->
filename:dirname(code:which(?MODULE)).
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
index 75b542b679..02c8d34361 100644
--- a/lib/diameter/test/diameter_examples_SUITE.erl
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -133,7 +133,7 @@ make(Path, Dict0) ->
try
ok = to_erl(Path, [{name, Name},
{prefix, Pre},
- {inherits, "rfc3588_base/" ++ Mod0}
+ {inherits, "common/" ++ Mod0}
| [{inherits, D ++ "/" ++ M ++ Suf}
|| {D,M} <- dep(Dict)]]),
ok = to_beam(Name)
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index 023c5307b2..9fda067f2b 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -18,5 +18,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 1.4.4
+DIAMETER_VSN = 1.5
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)