Node
API reference for diameter.node
.
Node ¶
Node(
origin_host: str,
realm_name: str,
ip_addresses: list[str] = None,
tcp_port: int = None,
sctp_port: int = None,
vendor_ids: list[int] = None,
)
A diameter node.
A single diameter node represents the local peer. It handles connections to other peers, exchanging capabilities-exchange, device-watchdog and disconnect-peer requests and answers on its own.
The node can act either as a server or as a client. In both cases it will handle both incoming and outgoing requests, however when acting as a client, other diameter nodes cannot connect to it, all connections must be initiated and managed by the client. When acting as a server, connections can be established by any party.
The node supports both TCP and SCTP transport modes. When acting as a server, it can always listen on multiple addresses, however this is only useful when utilising SCTP, as other peers will only connect to a single TCP address at a time.
The node can connect to multiple peers simultaneously; peers can be added
using Node.add_peer
. Both TCP and SCTP
transport modes are accepted and can be mixed at will. Peers can be flagged
as persistent, in which case the Node will periodically attempt to
reconnect, if a connection is lost.
>>> node = Node()
>>> node.add_peer("aaa://dra1.gy:3868;transport=tcp", "realm.net", ["10.16.17.5"])
>>> node.add_peer("aaa://dra2.gy;transport=sctp", "realm.net", ["10.16.17.6", "172.16.0.6"])
>>> node.start()
Any other message than CER/CEA, DWR/DWA and DPR/DPA will be routed to a diameter application that is expected to do the actual work. Applications can be created by subclassing either diameter.node.application.Application or diameter.node.application.ThreadingApplication and adding them to this node using add_application. If a message is received that is intended for an application that does not exist, a diameter error is returned to the peer.
Outgoing requests are routed based on realm and peer routing tables; if a request does not contain the Destination-Host AVP, the request is forwarded to a peer that has a matching realm and application ID set. If multiple peers are available, a rudimentary load balancing based on least used connections is used. Answers are routed back to the peer that they originated from, or dropped if the peer has gone away.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
origin_host
|
str
|
Our local node FQDN, must include the realm |
required |
realm_name
|
str
|
Realm FQDN |
required |
ip_addresses
|
list[str]
|
An optional list of IP address that the node will listen on for incoming requests. Must be set if the node is to act as a server. When not set, the node will not listen for any incoming connection attempts. |
None
|
tcp_port
|
int
|
An optional TCP listen port, should be set if
|
None
|
sctp_port
|
int
|
An optional SCTP listen port, should be set if
|
None
|
vendor_ids
|
list[int]
|
List of supported vendor IDs. If not set, will default to all known vendor IDs. The list of vendor IDs is only used in advertising the node's capabilities in CER/CEA |
None
|
applications
instance-attribute
¶
applications: list[Application] = []
List of configured applications.
cea_timeout
instance-attribute
¶
cea_timeout: int = 4
Default timeout waiting for a CEA after sending a CER, in seconds. Will be used if no specific timeout value has been configured for a peer.
cer_timeout
instance-attribute
¶
cer_timeout: int = 4
Default timeout waiting for a CER after receiving a connection attempt, in seconds. Will be used if no specific timeout value has been configured for a peer
connections
instance-attribute
¶
connections: dict[str, PeerConnection] = {}
Currently handled peer connections.
dwa_timeout
instance-attribute
¶
dwa_timeout: int = 4
Default timeout waiting for a DWA after sending a DWR, in seconds. Will be used if no specific timeout value has been configured for a peer.
end_to_end_seq
instance-attribute
¶
end_to_end_seq = SequenceGenerator(state_id)
An end-to-end identifier generator. The next identifier can be
retrieved with Node.end_to_end_seq.next_sequence()
.
idle_timeout
instance-attribute
¶
idle_timeout: int = 30
Default time spent idle before a DWR is triggered, in seconds. Will be used if no specific timeout value has been configured for a peer.
peer_sockets
instance-attribute
¶
peer_sockets: dict[str, socket | sctpsocket] = {}
Currently held sockets, one for each peer connection.
peers
instance-attribute
¶
peers: dict[str, Peer] = {}
All currently known peers as a dictionary of host identities as
keys and instances of Peer
as values..
peers_logging
instance-attribute
¶
peers_logging: bool = False
If enabled, will dump a JSON representation of each peer
configuration and their current connection status, at every
wakeup_interval
seconds. The logging will be done through
"diameter.stats" log facility an can also be silenced by changing the
log level to anything above DEBUG.
retransmit_queue_size
instance-attribute
¶
retransmit_queue_size: int = 10240
The amount of request end-to-end identifiers to "remember" after
sending an answer. The list of remembered identifiers is checked every
time a request with the "T" flag is received. The request will be
rejected if a matching end-to-end identifier is still present in the
queue. The size of this should match roughly with the amount of
requests that are expected to arrive within a time period that
retransmits may arrive. There is no noticeable performance loss when
setting this higher than the default value of 10240
.
session_generator
instance-attribute
¶
session_generator = SessionGenerator(origin_host)
A unique diameter session ID generator. The next unique session
ID can be retrieved Node.session_generator.next_id()
.
socket_peers
instance-attribute
¶
socket_peers: dict[int, PeerConnection] = {}
Peer connection lookup based on socket fileno.
statistics
property
¶
statistics: NodeStats
Calculated, cumulated and averaged statistics for the entire node.
statistics_history
instance-attribute
¶
statistics_history: deque[dict] = deque(maxlen=1440)
A list of node statistics snapshots, taken at one minute intervals and kept for 24 hours. Each snapshot is a dictionary representation of a NodeStats instance.
stats_logging
instance-attribute
¶
stats_logging: bool = False
If enabled, will dump a JSON representation of the statistics for
each peer in the logs, at every wakeup_interval
seconds. The
logging will be done through "diameter.stats" log facility an can
also be silenced by changing the log level to anything above DEBUG.
Enabling this may have a slight performance impact, as the main
thread will block while the statistics are being gathered.
wakeup_interval
instance-attribute
¶
wakeup_interval: int = 6
Time in seconds between forced wakeups while waiting for connection sockets to become active. This timer value controls how often peer timers are checked, how often reconnects are attempted and how often statistics are dumped in the logfiles.
As this also defines the interval at which peer timers are checked, it is also the smallest possible value for a peer timer value. Setting this value very low will consume more CPU, setting it too high will make observing short timeouts impossible.
This value also defines how long a node will continue to run, after
stop
with force
argument set to True
is called.
add_application ¶
add_application(
app: Application, peers: list[Peer], realms: list[str] = None
)
Register an application with diameter node.
The added application will receive diameter requests that the node receives, which an application-id message header value matching the application's ID.
When added, the node calls the application's start
method
immediately. The application is stopped when the node stops.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
app
|
Application
|
An instance of a class that implements
|
required |
peers
|
list[Peer]
|
A list of Peer instances that have been returned by
|
required |
realms
|
list[str]
|
An optional list of realms served for the peers through
the application, in addition to the realm name given as part of
|
None
|
add_peer ¶
add_peer(
peer_uri: str,
realm_name: str = None,
ip_addresses: list[str] = None,
is_persistent: bool = False,
is_default: bool = False,
) -> Peer
Add a known peer.
The node will only connect to known connections and (optionally) accept requests from known connections only.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
peer_uri
|
str
|
A diameter node's DiameterIdentity as a DiameterURI
string, i.e. "aaa:// |
required |
realm_name
|
str
|
Peer realm name. If not given, will be set to the same realm as the node has been configured with |
None
|
ip_addresses
|
list[str]
|
A list of IP addresses for the peer. If not given, no outgoing connection attempt to the peer will be made. For TCP, only the first IP of the list is used. For SCTP, a connection will be established to every address |
None
|
is_persistent
|
bool
|
Enable persistent connection to the peer. If enabled, the node will automatically re-establish a connection to the peer on startup and at connection loss |
False
|
is_default
|
bool
|
Set this peer as the default peer for the realm. Note that multiple defaults is permitted. Setting multiple pers as default will result in load balancing between the peers. |
False
|
Returns:
Type | Description |
---|---|
Peer
|
An instance of the peer. The returned instance is the actual peer instance, permitting configuration to be adjusted after node has been started, by altering its attributes. |
close_connection_socket ¶
close_connection_socket(
conn: PeerConnection,
disconnect_reason: int = DISCONNECT_REASON_UNKNOWN,
)
Shuts down connection socket and stops observing it forever.
If the corresponding peer has persistency enabled, the node will
automatically re-establish the connection after Node.reconnect_timeout
seconds.
Closing the peer socket will automatically call
Node.remove_peer_connection
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
conn
|
PeerConnection
|
An instance of a peer connection to disconnect |
required |
disconnect_reason
|
int
|
Reason for the connection being disconnected,
one of the |
DISCONNECT_REASON_UNKNOWN
|
remove_peer_connection ¶
remove_peer_connection(
conn: PeerConnection,
disconnect_reason: int = DISCONNECT_REASON_UNKNOWN,
)
Removes a peer connection that is no longer connected.
Warning
This method should not be called directly, unless it is absolutely
certain that the peer socket is no longer connected. The safer way
is to use Node.close_connection_socket
instead, which will first close the socket and then remove the peer.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
conn
|
PeerConnection
|
An instance of peer connection to remove from the list of active connections |
required |
disconnect_reason
|
int
|
A reason for the connection being disconnected,
one of the |
DISCONNECT_REASON_UNKNOWN
|
route_answer ¶
route_answer(message: Message) -> tuple[PeerConnection, Message]
Determine which peer should be used for sending an answer message.
Should always be used by an application before sending an answer.
Determines the proper peer to be used, by keeping track of which requests have been sent, and always forwarding answers in reverse direction to correct peer connections.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
message
|
Message
|
The exact answer message to send |
required |
Returns:
Type | Description |
---|---|
tuple[PeerConnection, Message]
|
A tuple with an instance of a peer to route to, and the same message as was passed to the method. |
Raises:
Type | Description |
---|---|
NotRoutable
|
when there is either no peer waiting for the answer, or when the peer exists, but does not accept messages at the time |
route_request ¶
route_request(
app: Application, message: Message
) -> tuple[PeerConnection, Message]
Determine which peer should be used for sending a request message.
Should always be used by an application before sending a request.
Determines the proper peer to be used for the particular message, by comparing the configured peer list with what is currently connected and ready to receive requests. If multiple connections are available, a rudimentary load balancing is used, with least-used peer selected.
Sets the hop-by-hop identifier automatically based on the selected peer.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
app
|
Application
|
The application instance that wants to send a request |
required |
message
|
Message
|
The exact message to send |
required |
Returns:
Type | Description |
---|---|
tuple[PeerConnection, Message]
|
A tuple with an instance of a peer to route to, and the same message as was passed to the method. |
Raises:
Type | Description |
---|---|
NotRoutable
|
when there is either no connections configured for the application, or if none of the configured connections is connected or accepting requests at the time |
send_message ¶
send_message(conn: PeerConnection, message: Message)
Manually send a message towards a peer.
Normally messages are sent through applications, but this method permits manually sending messages towards known connections.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
conn
|
PeerConnection
|
An instance of a peer connection to send the message to. The
connection must be in |
required |
message
|
Message
|
A valid diameter message instance to send, can be either a request or an answer. |
required |
start ¶
start()
Start the node.
This method must be called once after the peer has been created. At startup, the node will create the local listening sockets, start its work threads and connect to any connections that have persistent connections enabled.
stop ¶
stop(wait_timeout: int = 180, force: bool = False)
Stop node.
Stopping the node will emit a Disconnect-PeerConnection-Request
towards each
currently connected peer, with disonnect cause "REBOOTING".
The node will then wait until each peer has produced a
Disconnect-PeerConnection-Answer
, and regardless of the answer's result code
or error status, the peer sockets are closed. Some diameter vendors
may also already close the socket from their end immediately, if no
messages are pending.
After all connections have disconnected, the node's own listening sockets will close, and afterwards the active applications are shut down.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
wait_timeout
|
int
|
Set a timeout for the DPR/DPA procedure to cpmplete. This should be usually fairly high, as time must be given for not only for the DPR/DPA messages to travel, but also for the peer connections to empty their in- and out buffers and for the applications to finish processing responses. |
180
|
force
|
bool
|
Optionally skip DPR/DPA procedure and just force each peer connection to close immediately, with a very short (5-10 seconds) wait period for their threads to join. |
False
|
NodeStats
dataclass
¶
NodeStats(
avg_response_time: dict[str, float],
avg_response_time_overall: float,
processed_req_per_second: dict[str, float],
processed_req_per_second_overall: float,
received_req_counters: list[int],
sent_result_code_range_counters: dict[str, list[int]],
)
Cumulated and averaged node statistics.
Represents a snapshot with cumulated and averaged statistical values for all configured peers at the time of retrieval. The meaning of each statistical value is identical to those of PeerStats.
avg_response_time
instance-attribute
¶
avg_response_time: dict[str, float]
Average response time, split by message type.
avg_response_time_overall
instance-attribute
¶
avg_response_time_overall: float
Overall average response time.
processed_req_per_second
instance-attribute
¶
processed_req_per_second: dict[str, float]
Rate of requests processed per second, split by message type.
processed_req_per_second_overall
instance-attribute
¶
processed_req_per_second_overall: float
Rate of requests processed per second.
received_req_counters
instance-attribute
¶
received_req_counters: list[int]
Exact amount of requests received in the last minute, last five minutes and the last 15 minutes.
sent_result_code_range_counters
instance-attribute
¶
sent_result_code_range_counters: dict[str, list[int]]
Exact amount of answers sent in the last minute, last five minutes and the last 15 minutes, once for each diameter result code range. The result code range is expressed as a string in form of "1xxx", "2xxx" etc.
NodeError ¶
Bases: Exception
Base error for all exceptions raised by Node
.