PFCP ==== The system provides a python object :data:`alc.pfcp`, an instance of class :data:`alc.Pfcp`, to inspect and modify the PFCP packets. .. note:: For PFCP message, only the pre-provided :data:`alc.pfcp` object should be used in script, the class :data:`alc.Pfcp` should not be used directly. .. _alc_dot_pfcp: The :data:`alc.Pfcp` class --------------------------- Instance Attributes ^^^^^^^^^^^^^^^^^^^ The PFCP header fields are exposed as instance attributes on the object. .. list-table:: Attributes of alc.pfcp :header-rows: 1 * - Attribute - Description - Access - Type * - flags - Complete flags field as an 8-bit integer - ro - int * - version - PFCP version - ro - int * - fo_flag - FO flag (follow on) marking another PFCP message follows in the same UDP frame - ro - bool * - mp_flag - Flag marking if there is a msg_priority field - ro - bool * - s_flag - Flag marking if there is a SEID field - ro - bool * - msg_type - Message type - ro - int * - msg_len - Message length - ro - int * - seid - Session Endpoint Identifier; `None` if the header field is not present - ro - int|None * - seq_number - Sequence number - ro - int * - msg_priority - Message priority; `None` if the header field is not present - ro - int|None Methods ^^^^^^^ .. method:: drop() Drops the packet. .. method:: get_ie_list() Returns a list of IE-types that are present in the packet. - The order of the elements is the same as they appear in the packet. - If there are multiple instances of the same IE, the IE-type appears multiple times in the tuple. :rtype: list .. method:: has(type, /) Returns if an IE of the specified type is present at the top-level. :param int type: IE-type to find :rtype: bool .. method:: get(type, /) Returns all values of the IEs with the specified type. The values are returned as the exact bytestrings as they appear in the packet. - If the specified type does not exist, the result is an empty tuple: () - If a specific instance has zero length or no values, the corresponding bytestring is an empty bytestring: b"" :param int type: IE-type to fetch :rtype: tuple of bytestrings .. method:: set(type, value, /) Replaces the currently present IEs of the specific type with new ones. Multiple values can be specified in a tuple in which case one IE with the specified type is added for each item in the tuple. :param int type: IE-type to set :param bytes|tuple(bytes) value: value of the IE; length is computed from this value .. method:: clear(type, /) Removes all IEs with the specified type. :param int type: IE-type to clear Constants ^^^^^^^^^ The :data:`alc.pfcp` object provides a list of following constants. .. list-table:: Message type constants defined on alc.pfcp :header-rows: 1 * - Name - Value * - MSG_TYPE_HEARTBEAT_REQ - 1 * - MSG_TYPE_HEARTBEAT_RESP - 2 * - MSG_TYPE_PFD_MGMT_REQ - 3 * - MSG_TYPE_PFD_MGMT_RESP - 4 * - MSG_TYPE_ASSOC_SETUP_REQ - 5 * - MSG_TYPE_ASSOC_SETUP_RESP - 6 * - MSG_TYPE_ASSOC_UPDATE_REQ - 7 * - MSG_TYPE_ASSOC_UPDATE_RESP - 8 * - MSG_TYPE_ASSOC_RELEASE_REQ - 9 * - MSG_TYPE_ASSOC_RELEASE_RESP - 10 * - MSG_TYPE_VERSION_NOT_SUP_RESP - 11 * - MSG_TYPE_NODE_REPORT_REQ - 12 * - MSG_TYPE_NODE_REPORT_RESP - 13 * - MSG_TYPE_SESSION_SET_DEL_REQ - 14 * - MSG_TYPE_SESSION_SET_DEL_RESP - 15 * - MSG_TYPE_SESSION_EST_REQ - 50 * - MSG_TYPE_SESSION_EST_RESP - 51 * - MSG_TYPE_SESSION_MOD_REQ - 52 * - MSG_TYPE_SESSION_MOD_RESP - 53 * - MSG_TYPE_SESSION_DEL_REQ - 54 * - MSG_TYPE_SESSION_DEL_RESP - 55 * - MSG_TYPE_SESSION_REPORT_REQ - 56 * - MSG_TYPE_SESSION_REPORT_RESP - 57 .. _alc_dot_pfcp_utils: The :mod:`alc.pfcp_utils` module --------------------------------- .. module:: alc.pfcp_utils Decoded IE classes ^^^^^^^^^^^^^^^^^^ The module comes with a list of pre-defined classes which represent a decoded IE. These classes known how to convert between a bytes-representation of a specific IE and a Python-object of that class that allows direct interaction with its value. * :class:`AbstractIE` * :class:`BasicIE` * :class:`IntegerIE` * :class:`StringIE` * :class:`GroupedIE` Other decoders can be created by subclassing the :class:`AbstractIE` class, providing a sensible `__init__` function and overriding the following two methods: * :meth:`AbstractIE.encode` * :meth:`AbstractIE.from_bytes` .. autoclass:: AbstractIE :members: :special-members: __eq__ .. autoclass:: BasicIE :members: .. autoclass:: IntegerIE :members: .. autoclass:: StringIE :members: .. autoclass:: GroupedIE :members: Decoding ^^^^^^^^ The module provides a function to decode a bytes representation of the value of an IE. This function can be passed in the result of a call to :meth:`alc.pfcp.get` as the value for the `iter_of_bytes` argument. .. autofunction:: decode_ies Examples -------- Example 1: Adding and removing IEs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: from alc import pfcp from pfcp_utils import IntegerIE, GroupedIE, BasicIE, StringIE # remove some IEs from the packet pfcp.clear(17) pfcp.clear(2) # create new IEs and insert them new_ies = [ IntegerIE(109, 4, 1), BasicIE(25, b'\x00'), GroupedIE(7, [qerid_ie, corrid_ie, gatestatus_ie]) ] for ie in new_ies: pfcp.set(ie.type, ie.encode()) # add multiple IEs of the same type pfcp.set(22, (StringIE(22, "ISP1").encode(), StringIE(22, "ISP2").encode())) Example 2: Fetching and decoding IEs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: from alc import pfcp from pfcp_utils import IntegerIE, decode_ies # fetch some IEs # result will be a tuple of bytestrings raw_qer_ies = pfcp.get(109) # decode them using an IntegerIE decoder qer_ies = decode_ies(109, raw_qer_ies, IntegerIE) Example 3: Working with grouped IEs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: from alc import pfcp from pfcp_utils import IntegerIE, GroupedIE, BasicIE, StringIE, decode_ies # Fetch a grouped IE and iterate its sub-IEs create_pdrs = decode_ies(1, pfcp.get(1), GroupedIE) for pdr in create_pdrs: for ie in pdr.sub_ies: print(ie) # You can pass in extra info about sub-IEs that you want to be decoded automatically # Notice that you can specify sub-IEs to be GroupedIE as well, which will cause the # decoding to recurse even further. sub_decoders = {2: GroupedIE, 20: IntegerIE} create_pdrs = decode_ies(1, pfcp.get(1), GroupedIE, sub_decoders = sub_decoders) # Find a specific sub-ie for pdr in create_pdrs: for pdi_ie in pdr.sub_ies_of_type(2): print(ie) # Find and modify specific sub-sub-ie: for pdr in create_pdrs: for pdi_ie in pdr.sub_ies_of_type(2): for src_iface_ie in pdi_ie.sub_ies_of_type(20): src_iface = src_iface_ie.value & 0x0f if src_iface == 1: src_iface = 2 # create a groupedIE qerid_ie = IntegerIE(109, 4, 1) corrid_ie = IntegerIE(28, 4, corrid) gatestatus_ie = BasicIE(25, b'\x00') qer_ie = GroupedIE(7, [qerid_ie, corrid_ie, gatestatus_ie]) # Add a sub-IE to an existing grouped IE: for pdr in create_pdrs: pdr.sub_ies.append(qerid_ie) # In order to propagate these changes into the pfcp-packet, the outer # GroupedIE needs to be encoded again and the resulting bytes has to be # set on the packet. alc.pfcp.set(1, tuple(ie.encode() for ie in create_pdrs))