Diameter ======== The system provides a Python object :data:`alc.diameter`, which is an instance of class :data:`alc.Diameter`, to inspect and modify Diameter packets. .. note:: Only the pre-provided :data:`alc.diameter` object should be used in script, the class :data:`alc.Diameter` should not be used directly. .. _alc_dot_diameter: The :data:`alc.Diameter` class ------------------------------- Terminology ^^^^^^^^^^^ The methods on the `alc.Diameter` class use a set of data representations for handling the AVPs. The terminology and corresponding data types are as follows: .. list-table:: Attributes defined on Diameter messages * - top-level-AVP - | AVP appearing at the top level in a Diameter message, | not embedded in the Data field of a grouped AVP * - embedded-AVP - | AVP embedded in the Data field of a grouped AVP. | An embedded AVP can be a grouped AVP; this is called nesting. * - AVP-tuple - (code, vendor, flags) tuple with types (int, int, bytes) * - AVP-value-tuple - (flags, data) tuple with types (bytes, bytes) * - AVP-key-tuple - (code, vendor) tuple with types (int, int) * - grouped-AVP-value-tuple - (flags, grouped_avps) tuple with types (bytes, grouped-AVP-dictionnary) * - grouped-AVP-dictionnary - dict of nested AVPs where: - keys are of type AVP-key-tuple - values are of type list[AVP-value-tuples] or list[grouped-AVP-value-tuples] Instance Attributes ^^^^^^^^^^^^^^^^^^^ DIAMETER header fields are exposed as instance attributes on the object. .. list-table:: Attributes defined on Diameter messages :header-rows: 1 * - Attribute - Access - Type * - version - rw - bytes * - msg_length - ro - bytes * - flags - rw - bytes * - code - rw - bytes * - application_id - rw - bytes * - hop_by_hop_id - rw - bytes * - end_to_end_id - rw - bytes Methods ^^^^^^^ .. method:: drop() Drops the Diameter message. The packet is consumed at TCP level (ack send). A drop triggers retransmissions at the Diameter level. .. method:: get_avps_list() Returns a list of AVP-tuples. Each AVP-tuple represents an instance of an AVP in the message. - Applies to top-level-AVPs only. - The position in the list corresponds with the position of the AVP in the message at that stage in the script. - When executed before any clear or set AVP method, the list order corresponds with the AVP order in the received message. - When multiple instances of an AVP are present in the message, multiple instances appear in the list. - The Vendor ID has value zero when not present. - Grouped AVPs cannot be distinguished from other AVPs in the list. :return: list of AVP-tuples :: print(alc.diameter.get_avps_list()) #[(263, 0, b'@'), (264, 0, b'@'), (296, 0, b'@'), (258, 0, b'@'), (416, 0, b'@'), (415, 0, b'@'), (268, 0, b'@'), (55, 0, b'@'), (456, 0, b'@'), (456, 0, b'@'), (456, 0, b'@'), (293, 0, b'@'), (256, 12645, b'\x80')] .. method:: get_avps(code, vendor, /) Returns a list of AVP-value-tuples. Each AVP-value-tuple represents an instance of the specified AVP in the message. - Applies to top-level-AVPs only. - The position in the list corresponds with the position of the AVP instance in the message at that stage in the script. - When executed before any clear or set AVP method, the list order corresponds with the AVP order in the received message. - If the specified AVP is a grouped AVP, the data contains all the embedded AVPs. - An empty list is returned if the specified AVP is not present. - The Vendor ID value zero matches top-level-AVPs without the Vendor ID field. :param int code: AVP code :param int vendor: AVP Vendor ID, the value zero matches AVPs without Vendor ID field :return: list of AVP-value-tuples :: print(alc.diameter.get_avps(263, 0)) #[('@', 'bng.nokia.com;1398156449;28')] .. method:: set_avps(code, vendor, values, /) Deletes existing top level AVPs of the specified code and vendor and inserts new AVPs vendor with the specified code, vendor and values. For each entry in the AVP-value-tuple list, a top-level-AVP instance is inserted. - If the specified Vendor ID value is zero, no Vendor ID field is inserted and setting the Vendor-Specific bit in the flags field of the AVP value tuple results in a Python error. - If the specified Vendor ID value is non-zero, a Vendor ID field is inserted. Not setting the Vendor-Specific bit in the flags field of the AVP value tuple results in a Python error. - Padding between AVPs, AVP length, and Diameter message length is adapted accordingly by the system. :param int code: AVP code :param int vendor: AVP Vendor ID, the value zero means not to insert a Vendor ID field :param values: list of AVP-value-tuples :: alc.diameter.set_avps(461, 0, [(b'\x40', b'Python-1'), (b'\x40', b'Python-2')]) .. method:: clear_avps(code, vendor, /) Removes all instances of the specified AVP from the message. - Applies to top-level-AVPs only. - If the specified AVP is not present, no Python error is generated. :param int code: AVP code :param int vendor: AVP Vendor ID, the value zero matches AVPs without Vendor-Id field :: d.clear_avps(256, 12645) .. method:: set_fixed_position_avps(avps, /) Places the specified top-level-AVPs at the beginning of the message. - AVPs are ordered as specified in the `avps` tuple. - AVPs not present in the message but specified in `avps` are ignored. - AVPs present in the message and not specified in `avps` are included in the final message after the AVPs listed in the ordered AVPs tuple. The order is deterministic but implementation specific. - This method can appear at any point in the script. The last call overrides the previous one. :param list avps: tuple of AVP-key-tuples .. note:: In Python 2, calling this function interferes with fetching AVPs in a subsequent `get_avp_list()` call. This restriction is no longer present in the Python 3 implementation. :: alc.diameter.set_fixed_position_avps([(263,0), (264,0), (296,0), (268,0)]) .. method:: get_grouped_avps(code, vendor, grouped_avps=(), /) Returns a list of grouped-AVP-value-tuples with each grouped-AVP-dictionary entry representing an embedded AVP. Each grouped-AVP-value-tuple represents an instance of the specified AVP in the message. - Applies to top-level-AVPs of type grouped only. - The position in the list corresponds with the position of the grouped AVP instance in the message at that stage in the script. When executed before any clear or set AVP method, the list order corresponds with the AVP order in the received message. - The position of the embedded AVPs in the grouped-AVP-dictionary does not correspond with the position in the grouped AVP. - If the `grouped_avps` argument is empty, only the top-level-AVP specified by `code` and `vendor` arguments is expanded. - To expand nested AVPs (grouped AVPs embedded in a grouped AVP), they must be specified as a tuple in the `grouped_avps` argument. :param int code: AVP code :param int vendor: AVP Vendor Id :param tuple grouped_avps: tuple of AVP-key-tuples listing which embedded AVPs need to be expanded recursively :returns: list of grouped-AVP-value-tuples :raises ValueError: when the top-level-AVP or one of the AVPs in the `grouped_avps` cannot be decoded as a grouped-avp. :: # To expand the Multiple Services Credit Control (456) grouped top level AVP: print(alc.diameter.get_grouped_avps(456, 0)) #[(b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x01')], (431, 0): [(b'@', b'\x00\x00\x01\xa4@\x00\x00\x0c\x00\x00\x00d')], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]}), (b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x02')], (431, 0): [(b'@', b'\x00\x00\x01\xa4@\x00\x00\x0c\x00\x00\x03\x84')], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]}), (b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x03')], (431, 0): [(b'@', b'\x00\x00\x01\xa4@\x00\x00\x0c\x00\x00\x00<')], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]})] # To expand the nested Granted-Service-Unit AVP (code 431) in the grouped Multiple Services Credit Control top level AVP (code 456): print(alc.diameter.get_grouped_avps(456, 0, ((456, 0), (431, 0)))) #[(b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x01')], (431, 0): [(b'@', {(420, 0): [(b'@', b'\x00\x00\x00d')]})], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]}), (b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x02')], (431, 0): [(b'@', {(420, 0): [(b'@', b'\x00\x00\x03\x84')]})], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]}), (b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x03')], (431, 0): [(b'@', {(420, 0): [(b'@', b'\x00\x00\x00<')]})], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]})] .. method:: set_grouped_avps(code, vendor, grouped_avps, /) Deletes existing grouped top level AVPs of the specified code and vendor and inserts new AVPs with the specified grouped_avps. - The order of the embedded-AVPs in the grouped AVP cannot be specified. - Padding between AVPs, AVP length, and Diameter message length is adjusted accordingly. :param int code: AVP code :param int vendor: AVP Vendor ID, the value zero means not to insert a Vendor ID field :param grouped_avps: list of grouped-AVP-value-tuples :: alc.diameter.set_grouped_avps(456,0,[(b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x01')], (431, 0): [(b'@', {(420, 0): [(b'@', b'\x00\x00\x00\x2b')]})], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]}), (b'@', {(432, 0): [(b'@', b'\x00\x00\x00\x03')], (431, 0): [(b'@', {(420, 0): [(b'@', b'\x00\x00\x00\x53')]})], (448, 0): [(b'@', b'\x00\x00\x04\xb0')], (268, 0): [(b'@', b'\x00\x00\x07\xd1')]})])