示例#1
0
    def test_attach_asr_tcp_data(self):
        """ attach + send ASR Req to session manager with a"""
        """ single UE """
        num_ues = 1
        self._s1ap_wrapper.configUEDevice(num_ues)
        datapath = get_datapath()

        req = self._s1ap_wrapper.ue_req
        print(
            "********************** Running End to End attach for ",
            "UE id ",
            req.ue_id,
        )
        # Now actually complete the attach
        self._s1ap_wrapper._s1_util.attach(
            req.ue_id,
            s1ap_types.tfwCmd.UE_END_TO_END_ATTACH_REQUEST,
            s1ap_types.tfwCmd.UE_ATTACH_ACCEPT_IND,
            s1ap_types.ueAttachAccept_t,
        )

        # Wait on EMM Information from MME
        self._s1ap_wrapper._s1_util.receive_emm_info()

        print("Sleeping for 5 seconds")
        time.sleep(5)

        print(
            "********************** Sending ASR for IMSI",
            "".join([str(i) for i in req.imsi]),
        )
        self._sessionManager_util.create_AbortSessionRequest(
            "IMSI" + "".join([str(i) for i in req.imsi]), )

        # Receive NW initiated detach request
        response = self._s1ap_wrapper.s1_util.get_response()
        self.assertEqual(
            response.msg_type,
            s1ap_types.tfwCmd.UE_NW_INIT_DETACH_REQUEST.value,
        )
        print("**************** Received NW initiated Detach Req")
        print("**************** Sending Detach Accept")

        # Send detach accept
        detach_accept = s1ap_types.ueTrigDetachAcceptInd_t()
        detach_accept.ue_Id = req.ue_id
        self._s1ap_wrapper._s1_util.issue_cmd(
            s1ap_types.tfwCmd.UE_TRIGGERED_DETACH_ACCEPT, detach_accept)

        print("Sleeping for 5 seconds")
        time.sleep(5)

        print("Checking that uplink/downlink flows were deleted")
        flows = get_flows(datapath, {
            "table_id": self.SPGW_TABLE,
            "priority": 0
        })
        self.assertEqual(len(flows), 2,
                         "There should only be 2 default table 0 flows")
示例#2
0
    def test_default_metering_flows(self):
        datapath = get_datapath()

        print('Checking for default table 3 flows')
        flows = get_flows(datapath, {
            'table_id': self.METERING_TABLE,
            'priority': 0
        })
        self.assertEqual(len(flows), 2,
                         'There should be 2 default table 3 flows')
示例#3
0
    def _verify_ue_metering_flows(self, ue):
        datapath = get_datapath()
        flows = get_flows(datapath, {
            'table_id': self.METERING_TABLE,
            'priority': 10
        })
        self.assertEqual(
            2, len(flows), 'There should be 2 UE metering flows, '
            'found {}'.format(len(flows)))

        ue_ip = str(self._s1ap_wrapper._s1_util.get_ip(ue.ue_id))
        self._verify_downlink_flow(flows, ue_ip)
        self._verify_uplink_flow(flows, ue_ip)
示例#4
0
def main():
    global datapath
    datapath = get_datapath()
    if not datapath:
        print("Coudn't get datapath")
        exit(1)

    parser = create_parser()
    # Parse the args
    args = parser.parse_args()
    if not args.cmd:
        parser.print_usage()
        exit(1)

    # Execute the subcommand function
    args.func(args)
示例#5
0
    def test_attach_detach_setsessionrules_tcp_data(self):
        """ Attach/detach + make set session rule calls to
        session manager twice + run UL and DL tcp traffic
        with a single UE """
        num_ues = 1
        self._s1ap_wrapper.configUEDevice(num_ues)
        datapath = get_datapath()
        MAX_NUM_RETRIES = 5

        internet = {
            "apn_name": "internet",  # APN-name
            "qci": 9,  # qci
            "priority": 15,  # priority
            "pre_cap": 0,  # preemption-capability
            "pre_vul": 0,  # preemption-vulnerability
            "mbr_ul": 100000,  # MBR UL
            "mbr_dl": 150000,  # MBR DL
        }

        # APN list to be configured
        apn_list = [internet]

        req = self._s1ap_wrapper.ue_req
        self._s1ap_wrapper.configAPN(
            "IMSI" + "".join([str(i) for i in req.imsi]),
            apn_list,
            default=False,
        )
        print(
            "********************** Running End to End attach for ",
            "UE id ",
            req.ue_id,
        )
        # Now actually complete the attach
        self._s1ap_wrapper._s1_util.attach(
            req.ue_id,
            s1ap_types.tfwCmd.UE_END_TO_END_ATTACH_REQUEST,
            s1ap_types.tfwCmd.UE_ATTACH_ACCEPT_IND,
            s1ap_types.ueAttachAccept_t,
        )

        # Wait on EMM Information from MME
        self._s1ap_wrapper._s1_util.receive_emm_info()

        # UL Flow description #1
        ulFlow1 = {
            "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
            "tcp_dst_port": 5001,  # TCP Server Port
            "direction": FlowMatch.UPLINK,  # Direction
        }

        # DL Flow description #1
        dlFlow1 = {
            "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
            "tcp_dst_port": 7001,  # TCP UE Port
            "direction": FlowMatch.DOWNLINK,  # Direction
        }

        ulFlow2 = {
            "ip_proto": FlowMatch.IPPROTO_UDP,  # Protocol Type
            "direction": FlowMatch.UPLINK,  # Direction
        }

        # DL Flow description #1
        dlFlow2 = {
            "ip_proto": FlowMatch.IPPROTO_UDP,  # Protocol Type
            "direction": FlowMatch.DOWNLINK,  # Direction
        }

        # Flow list to be configured
        flow_list = [
            ulFlow1,
            dlFlow1,
            ulFlow2,
            dlFlow2,
        ]

        # QoS
        max_bw_ul = 20000
        max_bw_dl = 35000
        qos = {
            "qci": 8,  # qci value [1 to 9]
            "priority": 0,  # Range [0-255]
            "max_req_bw_ul": max_bw_ul,  # MAX bw Uplink
            "max_req_bw_dl": max_bw_dl,  # MAX bw Downlink
            "gbr_ul": 1000,  # GBR Uplink
            "gbr_dl": 2000,  # GBR Downlink
            "arp_prio": 15,  # ARP priority
            "pre_cap": 1,  # pre-emption capability
            "pre_vul": 1,  # pre-emption vulnerability
        }

        policy_id = "tcp_udp_1"

        print("Sleeping for 5 seconds")
        time.sleep(5)
        print(
            "********************** Set Session Rule for IMSI",
            "".join([str(i) for i in req.imsi]),
        )
        self._sessionManager_util.send_SetSessionRules(
            "IMSI" + "".join([str(i) for i in req.imsi]),
            policy_id,
            flow_list,
            qos,
        )

        # Receive Activate dedicated bearer request
        response = self._s1ap_wrapper.s1_util.get_response()
        self.assertEqual(
            response.msg_type,
            s1ap_types.tfwCmd.UE_ACT_DED_BER_REQ.value,
        )
        act_ded_ber_ctxt_req = response.cast(
            s1ap_types.UeActDedBearCtxtReq_t, )

        # Send Activate dedicated bearer accept
        self._s1ap_wrapper.sendActDedicatedBearerAccept(
            req.ue_id,
            act_ded_ber_ctxt_req.bearerId,
        )

        policy_id = "tcp_udp_2"
        print("Sleeping for 5 seconds")
        time.sleep(5)
        print(
            "********************** Set Session Rule for IMSI",
            "".join([str(i) for i in req.imsi]),
        )
        self._sessionManager_util.send_SetSessionRules(
            "IMSI" + "".join([str(i) for i in req.imsi]),
            policy_id,
            flow_list,
            qos,
        )
        # First rule is replaced by the second rule
        # Triggers a delete bearer followed by a create bearer request
        # Receive Deactivate dedicated bearer request
        response = self._s1ap_wrapper.s1_util.get_response()
        self.assertEqual(
            response.msg_type,
            s1ap_types.tfwCmd.UE_DEACTIVATE_BER_REQ.value,
        )
        deactivate_ber_ctxt_req = response.cast(
            s1ap_types.UeDeActvBearCtxtReq_t, )

        # Send Deactivate dedicated bearer accept
        self._s1ap_wrapper.sendDeactDedicatedBearerAccept(
            req.ue_id,
            deactivate_ber_ctxt_req.bearerId,
        )

        # Receive Activate dedicated bearer request
        response = self._s1ap_wrapper.s1_util.get_response()
        self.assertEqual(
            response.msg_type,
            s1ap_types.tfwCmd.UE_ACT_DED_BER_REQ.value,
        )
        act_ded_ber_ctxt_req = response.cast(
            s1ap_types.UeActDedBearCtxtReq_t, )

        # Send Activate dedicated bearer accept
        self._s1ap_wrapper.sendActDedicatedBearerAccept(
            req.ue_id,
            act_ded_ber_ctxt_req.bearerId,
        )

        print("Sleeping for 2 seconds")
        time.sleep(2)
        # Check if UL and DL OVS flows are created
        gtp_br_util = GTPBridgeUtils()
        gtp_port_no = gtp_br_util.get_gtp_port_no()
        # UPLINK
        print("Checking for uplink flow")
        # try at least 5 times before failing as gateway
        # might take some time to install the flows in ovs
        for i in range(MAX_NUM_RETRIES):
            print("Get uplink flows: attempt ", i)
            uplink_flows = get_flows(
                datapath,
                {
                    "table_id": self.SPGW_TABLE,
                    "match": {
                        "in_port": gtp_port_no
                    },
                },
            )
            if len(uplink_flows) > 1:
                break
            time.sleep(5)  # sleep for 5 seconds before retrying

        assert len(uplink_flows) == 2, "There should be 2 UL flow rules for UE"
        self.assertIsNotNone(
            uplink_flows[0]["match"]["tunnel_id"],
            "Uplink flow missing tunnel id match",
        )
        self.assertIsNotNone(
            uplink_flows[1]["match"]["tunnel_id"],
            "Uplink flow missing tunnel id match",
        )

        # DOWNLINK
        print("Checking for downlink flow")
        ue_ip = str(self._s1ap_wrapper._s1_util.get_ip(req.ue_id))
        # try at least 5 times before failing as gateway
        # might take some time to install the flows in ovs
        for i in range(MAX_NUM_RETRIES):
            print("Get downlink flows: attempt ", i)
            downlink_flows = get_flows(
                datapath,
                {
                    "table_id": self.SPGW_TABLE,
                    "match": {
                        "nw_dst": ue_ip,
                        "eth_type": 2048,
                        "in_port": self.LOCAL_PORT,
                    },
                },
            )
            if len(downlink_flows) > 1:
                break
            time.sleep(5)  # sleep for 5 seconds before retrying

        assert len(
            downlink_flows) == 3, "Downlink flows must have been 3 for UE"
        self.assertEqual(
            downlink_flows[0]["match"]["ipv4_dst"],
            ue_ip,
            "UE IP match missing from downlink flow",
        )

        actions = downlink_flows[0]["instructions"][0]["actions"]
        has_tunnel_action = any(action for action in actions
                                if action["field"] == "tunnel_id"
                                and action["type"] == "SET_FIELD")
        self.assertTrue(
            has_tunnel_action,
            "Downlink flow missing set tunnel action",
        )

        # Get UL Flow Rule for TCP flows for verifying rate limits enforced
        print(
            "**********************Get uplink TCP flow for UE before UL traffic test:"
        )
        uplink_flow_b = get_flows(
            datapath,
            {
                "table_id": self.SPGW_TABLE,
                "match": {
                    "in_port": gtp_port_no
                },
                "priority": 65535,
            },
        )
        print(uplink_flow_b)

        with self._s1ap_wrapper.configUplinkTest(req,
                                                 duration=20,
                                                 is_udp=False) as test:
            test.verify()

        # Get UL Flow Rule for TCP flows for verifying rate limits enforced
        print(
            "**********************Get uplink TCP flow for UE after UL traffic test:"
        )
        uplink_flow_a = get_flows(
            datapath,
            {
                "table_id": self.SPGW_TABLE,
                "match": {
                    "in_port": gtp_port_no
                },
                "priority": 65535,
            },
        )
        print(uplink_flow_a)
        tcp_bytes = (uplink_flow_a[0]['byte_count'] -
                     uplink_flow_b[0]['byte_count'])
        tcp_time = (uplink_flow_a[0]['duration_sec'] -
                    uplink_flow_b[0]['duration_sec'])
        tcp_rate = 8 * tcp_bytes / tcp_time
        print("TCP UL Rate from OVS: %.2fbps" % tcp_rate)
        # Allow for a 10% error margin
        assert 0.9 * tcp_rate < max_bw_ul, "UL Rate for TCP flow violates UL rate policy for UE"

        # Get DL Flow Rule for TCP flows for verifying rate limits enforced
        print(
            "**********************Get downlink TCP flow for UE before DL traffic test:"
        )
        downlink_flow_b = get_flows(
            datapath,
            {
                "table_id": self.SPGW_TABLE,
                "match": {
                    "ipv4_dst": ue_ip,
                    "eth_type": 2048,
                    "in_port": self.LOCAL_PORT,
                    "ip_proto": FlowMatch.IPPROTO_TCP,
                    "tcp_dst": 7001,
                },
            },
        )
        print(downlink_flow_b)

        with self._s1ap_wrapper.configDownlinkTest(req,
                                                   duration=20,
                                                   is_udp=False) as test:
            test.verify()

        # Get DL Flow Rule for TCP flows for verifying rate limits enforced
        print(
            "**********************Get downlink TCP flow for UE after DL traffic test:"
        )
        downlink_flow_a = get_flows(
            datapath,
            {
                "table_id": self.SPGW_TABLE,
                "match": {
                    "ipv4_dst": ue_ip,
                    "eth_type": 2048,
                    "in_port": self.LOCAL_PORT,
                    "ip_proto": FlowMatch.IPPROTO_TCP,
                    "tcp_dst": 7001,
                },
            },
        )
        print(downlink_flow_a)
        tcp_bytes = (downlink_flow_a[0]['byte_count'] -
                     downlink_flow_b[0]['byte_count'])
        tcp_time = (downlink_flow_a[0]['duration_sec'] -
                    downlink_flow_b[0]['duration_sec'])
        tcp_rate = 8 * tcp_bytes / tcp_time
        print("TCP DL Rate from OVS: %.2fbps" % tcp_rate)
        # Allow for a 10% error margin
        assert 0.9 * tcp_rate < max_bw_dl, "DL Rate for TCP flow violates DL rate policy for UE"
        time.sleep(2)  # sleep for 2 seconds before detaching

        print(
            "********************** Running UE detach for UE id ",
            req.ue_id,
        )
        # Now detach the UE
        self._s1ap_wrapper.s1_util.detach(
            req.ue_id,
            s1ap_types.ueDetachType_t.UE_NORMAL_DETACH.value,
            True,
        )

        # Verify that all UL/DL flows are deleted
        self._s1ap_wrapper.s1_util.verify_flow_rules_deletion()
示例#6
0
class S1ApUtil(object):
    """
    Helper class to wrap the initialization and API interface of S1APTester
    Note that some of the values that are not that interesting are set
    through config files, that this class doesn't override. Examples include
    the various interface timeout params.
    """

    # Extracted from TestCntlrApp/src/ueApp/ue_esm.h
    CM_ESM_PDN_IPV4 = 0b01
    CM_ESM_PDN_IPV6 = 0b10
    CM_ESM_PDN_IPV4V6 = 0b11

    PROT_CFG_CID_PCSCF_IPV6_ADDR_REQUEST = 0x0001
    PROT_CFG_CID_PCSCF_IPV4_ADDR_REQUEST = 0x000C
    PROT_CFG_CID_DNS_SERVER_IPV6_ADDR_REQUEST = 0x0003

    lib_name = "libtfw.so"

    _cond = threading.Condition()
    _msg = Queue()

    MAX_NUM_RETRIES = 5
    datapath = get_datapath()
    SPGW_TABLE = 0
    LOCAL_PORT = "LOCAL"

    class Msg(object):
        def __init__(self, msg_type, msg_p, msg_len):
            self.msg_type = msg_type
            self.msg_p = ctypes.create_string_buffer(msg_len)
            ctypes.memmove(self.msg_p, msg_p, msg_len)
            self.msg_len = msg_len

        def cast(self, msg_class):
            return ctypes.cast(self.msg_p, ctypes.POINTER(msg_class)).contents

    @staticmethod
    def s1ap_callback(msg_type, msg_p, msg_len):
        """ S1ap tester compatible callback"""
        with S1ApUtil._cond:
            S1ApUtil._msg.put(S1ApUtil.Msg(msg_type, msg_p, msg_len))
            S1ApUtil._cond.notify_all()

    def __init__(self):
        """
        Initialize the s1aplibrary and its callbacks.
        """
        lib_path = os.environ["S1AP_TESTER_ROOT"]
        lib = os.path.join(lib_path, "bin", S1ApUtil.lib_name)
        os.chdir(lib_path)
        self._test_lib = ctypes.cdll.LoadLibrary(lib)
        self._callback_type = ctypes.CFUNCTYPE(None, ctypes.c_short,
                                               ctypes.c_void_p, ctypes.c_short)
        # Maintain a reference to the function object so GC doesn't release it.
        self._callback_fn = self._callback_type(S1ApUtil.s1ap_callback)
        self._test_lib.initTestFrameWork(self._callback_fn)
        self._test_api = self._test_lib.tfwApi
        self._test_api.restype = ctypes.c_int16
        self._test_api.argtypes = [ctypes.c_uint16, ctypes.c_void_p]

        # Mutex for state change operations
        self._lock = threading.RLock()

        # Maintain a map of UE IDs to IPs
        self._ue_ip_map = {}
        self.gtpBridgeUtil = GTPBridgeUtils()

    def cleanup(self):
        """
        Cleanup the dll loaded explicitly so the next run doesn't reuse the
        same globals as ctypes LoadLibrary uses dlopen under the covers

        Also clear out the UE ID: IP mappings
        """
        # self._test_lib.dlclose(self._test_lib._handle)
        self._test_lib = None
        self._ue_ip_map = {}

    def issue_cmd(self, cmd_type, req):
        """
        Issue a command to the s1aptester and blocks until response is recvd.
        Args:
            cmd_type: The cmd type enum
            req: The request Structure
        Returns:
            None
        """
        c_req = None
        if req:
            # For non NULL requests obtain the address.
            c_req = ctypes.byref(req)
        with self._cond:
            rc = self._test_api(cmd_type.value, c_req)
            if rc:
                logging.error("Error executing command %s" % repr(cmd_type))
                return rc
        return 0

    def get_ip(self, ue_id):
        """ Returns the IP assigned to a given UE ID

        Args:
            ue_id: the ue_id to query

        Returns an ipaddress.ip_address for the given UE ID, or None if no IP
        has been observed to be assigned to this IP
        """
        with self._lock:
            if ue_id in self._ue_ip_map:
                return self._ue_ip_map[ue_id]
            return None

    def get_response(self):
        # Wait until callback is invoked.
        return self._msg.get(True)

    def populate_pco(self,
                     protCfgOpts_pr,
                     pcscf_addr_type=None,
                     dns_ipv6_addr=False):
        """
        Populates the PCO values.
        Args:
            protCfgOpts_pr: PCO structure
            pcscf_addr_type: ipv4/ipv6/ipv4v6 flag
            dns_ipv6_addr: True/False flag
        Returns:
            None
        """
        # PCO parameters
        # Presence mask
        protCfgOpts_pr.pres = 1
        # Length
        protCfgOpts_pr.len = 4
        # Configuration protocol
        protCfgOpts_pr.cfgProt = 0
        # Extension bit for the additional parameters
        protCfgOpts_pr.ext = 1
        # Number of protocol IDs
        protCfgOpts_pr.numProtId = 0

        # Fill Number of container IDs and Container ID
        idx = 0
        if pcscf_addr_type == "ipv4":
            protCfgOpts_pr.numContId += 1
            protCfgOpts_pr.c[
                idx].cid = S1ApUtil.PROT_CFG_CID_PCSCF_IPV4_ADDR_REQUEST
            idx += 1

        elif pcscf_addr_type == "ipv6":
            protCfgOpts_pr.numContId += 1
            protCfgOpts_pr.c[
                idx].cid = S1ApUtil.PROT_CFG_CID_PCSCF_IPV6_ADDR_REQUEST
            idx += 1

        elif pcscf_addr_type == "ipv4v6":
            protCfgOpts_pr.numContId += 2
            protCfgOpts_pr.c[
                idx].cid = S1ApUtil.PROT_CFG_CID_PCSCF_IPV4_ADDR_REQUEST
            idx += 1
            protCfgOpts_pr.c[
                idx].cid = S1ApUtil.PROT_CFG_CID_PCSCF_IPV6_ADDR_REQUEST
            idx += 1

        if dns_ipv6_addr:
            protCfgOpts_pr.numContId += 1
            protCfgOpts_pr.c[
                idx].cid = S1ApUtil.PROT_CFG_CID_DNS_SERVER_IPV6_ADDR_REQUEST

    def attach(
        self,
        ue_id,
        attach_type,
        resp_type,
        resp_msg_type,
        sec_ctxt=s1ap_types.TFW_CREATE_NEW_SECURITY_CONTEXT,
        id_type=s1ap_types.TFW_MID_TYPE_IMSI,
        eps_type=s1ap_types.TFW_EPS_ATTACH_TYPE_EPS_ATTACH,
        pdn_type=1,
        pcscf_addr_type=None,
        dns_ipv6_addr=False,
    ):
        """
        Given a UE issue the attach request of specified type

        Caches the assigned IP address, if any is assigned

        Args:
            ue_id: The eNB ue_id
            attach_type: The type of attach e.g. UE_END_TO_END_ATTACH_REQUEST
            resp_type: enum type of the expected response
            sec_ctxt: Optional param allows for the reuse of the security
                context, defaults to creating a new security context.
            id_type: Optional param allows for changing up the ID type,
                defaults to s1ap_types.TFW_MID_TYPE_IMSI.
            eps_type: Optional param allows for variation in the EPS attach
                type, defaults to s1ap_types.TFW_EPS_ATTACH_TYPE_EPS_ATTACH.
            pdn_type:1 for IPv4, 2 for IPv6 and 3 for IPv4v6
            pcscf_addr_type:IPv4/IPv6/IPv4v6
        """
        attach_req = s1ap_types.ueAttachRequest_t()
        attach_req.ue_Id = ue_id
        attach_req.mIdType = id_type
        attach_req.epsAttachType = eps_type
        attach_req.useOldSecCtxt = sec_ctxt
        attach_req.pdnType_pr.pres = True
        attach_req.pdnType_pr.pdn_type = pdn_type

        # Populate PCO only if pcscf_addr_type is set
        if pcscf_addr_type or dns_ipv6_addr:
            self.populate_pco(attach_req.protCfgOpts_pr, pcscf_addr_type,
                              dns_ipv6_addr)
        assert self.issue_cmd(attach_type, attach_req) == 0

        response = self.get_response()

        # The MME actually sends INT_CTX_SETUP_IND and UE_ATTACH_ACCEPT_IND in
        # one message, but the s1aptester splits it and sends the tests 2
        # messages. Usually context setup comes before attach accept, but
        # it's possible it may happen the other way
        if s1ap_types.tfwCmd.INT_CTX_SETUP_IND.value == response.msg_type:
            response = self.get_response()
        elif s1ap_types.tfwCmd.UE_ATTACH_ACCEPT_IND.value == response.msg_type:
            context_setup = self.get_response()
            assert (context_setup.msg_type ==
                    s1ap_types.tfwCmd.INT_CTX_SETUP_IND.value)

        logging.debug(
            "s1ap response expected, received: %d, %d",
            resp_type.value,
            response.msg_type,
        )
        assert resp_type.value == response.msg_type

        msg = response.cast(resp_msg_type)

        # We only support IPv4 right now, as max PDN address in S1AP tester is
        # currently 13 bytes, which is too short for IPv6 (which requires 16)
        if resp_msg_type == s1ap_types.ueAttachAccept_t:
            pdn_type = msg.esmInfo.pAddr.pdnType
            addr = msg.esmInfo.pAddr.addrInfo
            if S1ApUtil.CM_ESM_PDN_IPV4 == pdn_type:
                # Cast and cache the IPv4 address
                ip = ipaddress.ip_address(bytes(addr[:4]))
                with self._lock:
                    self._ue_ip_map[ue_id] = ip
            elif S1ApUtil.CM_ESM_PDN_IPV6 == pdn_type:
                print("IPv6 PDN type received")
            elif S1ApUtil.CM_ESM_PDN_IPV4V6 == pdn_type:
                print("IPv4v6 PDN type received")
        return msg

    def receive_emm_info(self):
        response = self.get_response()
        logging.debug(
            "s1ap message expected, received: %d, %d",
            s1ap_types.tfwCmd.UE_EMM_INFORMATION.value,
            response.msg_type,
        )
        assert response.msg_type == s1ap_types.tfwCmd.UE_EMM_INFORMATION.value

    def detach(self, ue_id, reason_type, wait_for_s1_ctxt_release=True):
        """ Given a UE issue a detach request """
        detach_req = s1ap_types.uedetachReq_t()
        detach_req.ue_Id = ue_id
        detach_req.ueDetType = reason_type
        assert (self.issue_cmd(s1ap_types.tfwCmd.UE_DETACH_REQUEST,
                               detach_req) == 0)
        if reason_type == s1ap_types.ueDetachType_t.UE_NORMAL_DETACH.value:
            response = self.get_response()
            assert (s1ap_types.tfwCmd.UE_DETACH_ACCEPT_IND.value ==
                    response.msg_type)

        # Now wait for the context release response
        if wait_for_s1_ctxt_release:
            response = self.get_response()
            assert s1ap_types.tfwCmd.UE_CTX_REL_IND.value == response.msg_type

        with self._lock:
            del self._ue_ip_map[ue_id]

    def _verify_dl_flow(self, dl_flow_rules=None):
        # try at least 5 times before failing as gateway
        # might take some time to install the flows in ovs

        # Verify the total number of DL flows for this UE ip address
        num_dl_flows = 1
        for key, value in dl_flow_rules.items():
            tcp_src_port = 0
            ip_proto = 0
            ue_ip6_str = None
            ue_ip_str = str(key)
            if key.version == 6:
                ue_ip6_str = ipaddress.ip_network((ue_ip_str + "/64"),
                                                  strict=False).with_netmask
            ue_ip_addr = ue_ip6_str if key.version == 6 else ue_ip_str
            dst_addr = "nw_dst" if key.version == 4 else "ipv6_dst"
            key_to_be_matched = "ipv4_src" if key.version == 4 else "ipv6_src"
            eth_typ = 2048 if key.version == 4 else 34525

            # Set to 1 for the default bearer
            total_num_dl_flows_to_be_verified = 1
            for item in value:
                for flow in item:
                    if (flow["direction"] == FlowMatch.DOWNLINK
                            and key_to_be_matched in flow):
                        total_num_dl_flows_to_be_verified += 1
            total_dl_ovs_flows_created = get_flows(
                self.datapath,
                {
                    "table_id": self.SPGW_TABLE,
                    "match": {
                        dst_addr: ue_ip_addr,
                        "eth_type": eth_typ,
                        "in_port": self.LOCAL_PORT,
                    },
                },
            )
            assert (len(total_dl_ovs_flows_created) ==
                    total_num_dl_flows_to_be_verified)

            # Now verify the rules for every flow
            for item in value:
                for flow in item:
                    if (flow["direction"] == FlowMatch.DOWNLINK
                            and key_to_be_matched in flow):
                        ip_src_addr = flow[key_to_be_matched]
                        ip_src = "ipv4_src" if key.version == 4 else "ipv6_src"
                        ip_dst = "ipv4_dst" if key.version == 4 else "ipv6_dst"
                        tcp_src_port = flow["tcp_src_port"]
                        ip_proto = flow["ip_proto"]
                        for i in range(self.MAX_NUM_RETRIES):
                            print("Get downlink flows: attempt ", i)
                            downlink_flows = get_flows(
                                self.datapath,
                                {
                                    "table_id": self.SPGW_TABLE,
                                    "match": {
                                        ip_dst: ue_ip_addr,
                                        "eth_type": eth_typ,
                                        "in_port": self.LOCAL_PORT,
                                        ip_src: ip_src_addr,
                                        "tcp_src": tcp_src_port,
                                        "ip_proto": ip_proto,
                                    },
                                },
                            )
                            if len(downlink_flows) >= num_dl_flows:
                                break
                            time.sleep(
                                5)  # sleep for 5 seconds before retrying
                        assert (len(downlink_flows) >=
                                num_dl_flows), "Downlink flow missing for UE"
                        assert downlink_flows[0]["match"][ip_dst] == ue_ip_addr
                        actions = downlink_flows[0]["instructions"][0][
                            "actions"]
                        has_tunnel_action = any(
                            action for action in actions
                            if action["field"] == "tunnel_id"
                            and action["type"] == "SET_FIELD")
                        assert bool(has_tunnel_action)

    def verify_flow_rules(self, num_ul_flows, dl_flow_rules=None):
        GTP_PORT = self.gtpBridgeUtil.get_gtp_port_no()
        # Check if UL and DL OVS flows are created
        print("************ Verifying flow rules")
        # UPLINK
        print("Checking for uplink flow")
        # try at least 5 times before failing as gateway
        # might take some time to install the flows in ovs
        for i in range(self.MAX_NUM_RETRIES):
            print("Get uplink flows: attempt ", i)
            uplink_flows = get_flows(
                self.datapath,
                {
                    "table_id": self.SPGW_TABLE,
                    "match": {
                        "in_port": GTP_PORT,
                    }
                },
            )
            if len(uplink_flows) == num_ul_flows:
                break
            time.sleep(5)  # sleep for 5 seconds before retrying
        assert len(uplink_flows) == num_ul_flows, "Uplink flow missing for UE"
        assert uplink_flows[0]["match"]["tunnel_id"] is not None

        # DOWNLINK
        print("Checking for downlink flow")
        self._verify_dl_flow(dl_flow_rules)

    def verify_paging_flow_rules(self, ip_list):
        # Check if paging flows are created
        print("************ Verifying paging flow rules")
        num_paging_flows_to_be_verified = 1
        for ip in ip_list:
            ue_ip_str = str(ip)
            print("Verifying paging flow for ip", ue_ip_str)
            for i in range(self.MAX_NUM_RETRIES):
                print("Get paging flows: attempt ", i)
                paging_flows = get_flows(
                    self.datapath,
                    {
                        "table_id": self.SPGW_TABLE,
                        "match": {
                            "nw_dst": ue_ip_str,
                            "eth_type": 2048,
                            "priority": 5,
                        },
                    },
                )
                if len(paging_flows) == num_paging_flows_to_be_verified:
                    break
                time.sleep(5)  # sleep for 5 seconds before retrying
            assert (len(paging_flows) == num_paging_flows_to_be_verified
                    ), "Paging flow missing for UE"

            # TODO - Verify that the action is to send to controller
            """controller_port = 4294967293
示例#7
0
 def __init__(self, requests, ovs_ip=LOCALHOST):
     self._requests = requests
     self._ovs_ip = ovs_ip
     self._datapath = get_datapath(ovs_ip)
示例#8
0
    def test_attach_detach_with_he(self):
        """ Attach/detach + send ReAuth Req to session manager with a
        single UE along with Header enrichment.
        This test validates that same data test wotks with HE policy
        applied.
        Header enrichment should be as transparent as possible.
        """
        num_ues = 1
        detach_type = [
            s1ap_types.ueDetachType_t.UE_NORMAL_DETACH.value,
            s1ap_types.ueDetachType_t.UE_SWITCHOFF_DETACH.value,
        ]
        wait_for_s1 = [True, False]
        self._s1ap_wrapper.configUEDevice(num_ues)
        datapath = get_datapath()
        MAX_NUM_RETRIES = 5
        gtp_br_util = GTPBridgeUtils()
        PROXY_PORT = gtp_br_util.get_proxy_port_no()
        utils = HeaderEnrichmentUtils()

        for i in range(num_ues):
            req = self._s1ap_wrapper.ue_req
            print(
                "********************** Running End to End attach for ",
                "UE id ",
                req.ue_id,
            )
            # Now actually complete the attach
            self._s1ap_wrapper._s1_util.attach(
                req.ue_id,
                s1ap_types.tfwCmd.UE_END_TO_END_ATTACH_REQUEST,
                s1ap_types.tfwCmd.UE_ATTACH_ACCEPT_IND,
                s1ap_types.ueAttachAccept_t,
            )

            # Wait on EMM Information from MME
            self._s1ap_wrapper._s1_util.receive_emm_info()

            # UL Flow description #1
            ulFlow1 = {
                "ipv4_dst": "192.168.129.42",  # IPv4 destination address
                "tcp_dst_port": 5002,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # Flow list to be configured
            flow_list = [
                ulFlow1,
            ]

            # QoS
            qos = {
                "qci": 5,  # qci value [1 to 9]
                "priority": 0,  # Range [0-255]
                "max_req_bw_ul": 10000000,  # MAX bw Uplink
                "max_req_bw_dl": 15000000,  # MAX bw Downlink
                "gbr_ul": 1000000,  # GBR Uplink
                "gbr_dl": 2000000,  # GBR Downlink
                "arp_prio": 15,  # ARP priority
                "pre_cap": 1,  # pre-emption capability
                "pre_vul": 1,  # pre-emption vulnerability
            }

            policy_id = "ims-voice"

            print("Sleeping for 5 seconds")
            time.sleep(5)
            imsi = "IMSI" + "".join([str(i) for i in req.imsi])

            he_domain1 = "192.168.129.42"
            assert utils.he_count_record_of_imsi_to_domain(imsi,
                                                           he_domain1) == 0

            print(
                "********************** Sending RAR for ",
                imsi,
            )
            self._sessionManager_util.send_ReAuthRequest(
                "IMSI" + "".join([str(i) for i in req.imsi]),
                policy_id,
                flow_list,
                qos,
                he_urls=HeaderEnrichment(urls=[he_domain1]),
            )

            # Receive Activate dedicated bearer request
            response = self._s1ap_wrapper.s1_util.get_response()
            self.assertEqual(
                response.msg_type,
                s1ap_types.tfwCmd.UE_ACT_DED_BER_REQ.value,
            )
            act_ded_ber_ctxt_req = response.cast(
                s1ap_types.UeActDedBearCtxtReq_t, )

            print("Sleeping for 5 seconds")
            time.sleep(5)
            # Send Activate dedicated bearer accept
            self._s1ap_wrapper.sendActDedicatedBearerAccept(
                req.ue_id,
                act_ded_ber_ctxt_req.bearerId,
            )

            # Check if UL and DL OVS flows are created
            # UPLINK
            print("Checking for uplink proxy flow for port: ", PROXY_PORT)
            # try at least 5 times before failing as gateway
            # might take some time to install the flows in ovs
            for i in range(MAX_NUM_RETRIES):
                uplink_flows = gtp_br_util.get_flows(self.HE_TABLE)
                if len(uplink_flows) > 1:
                    break
                time.sleep(1)  # sleep for 5 seconds before retrying

            assert len(uplink_flows) > 1, "HE flow missing for UE"

            assert utils.he_count_record_of_imsi_to_domain(imsi,
                                                           he_domain1) == 1

            print(
                "********************** Deleting dedicated bearer for IMSI",
                "".join([str(i) for i in req.imsi]),
            )
            self._spgw_util.delete_bearer(
                "IMSI" + "".join([str(i) for i in req.imsi]),
                5,
                6,
            )

            response = self._s1ap_wrapper.s1_util.get_response()
            self.assertEqual(
                response.msg_type,
                s1ap_types.tfwCmd.UE_DEACTIVATE_BER_REQ.value,
            )

            print("******************* Received deactivate eps bearer context")

            deactv_bearer_req = response.cast(s1ap_types.UeDeActvBearCtxtReq_t)
            self._s1ap_wrapper.sendDeactDedicatedBearerAccept(
                req.ue_id,
                deactv_bearer_req.bearerId,
            )

            print("Sleeping for 5 seconds")
            time.sleep(5)

            print(
                "********************** Running UE detach for UE id ",
                req.ue_id,
            )
            # Now detach the UE
            self._s1ap_wrapper.s1_util.detach(
                req.ue_id,
                detach_type[i],
                wait_for_s1[i],
            )

            time.sleep(20)
            assert utils.he_count_record_of_imsi_to_domain(imsi,
                                                           he_domain1) == 0

        # Verify that all UL/DL flows are deleted
        self._s1ap_wrapper.s1_util.verify_flow_rules_deletion()
示例#9
0
    def test_attach_detach_with_ovs(self):
        """
        Basic sanity check of UE downlink/uplink flows during attach and
        detach procedures.
        """
        datapath = get_datapath()
        MAX_NUM_RETRIES = 5

        print("Checking for default table 0 flows")
        flows = get_flows(datapath, {
            "table_id": self.SPGW_TABLE,
            "priority": 0
        })
        self.assertEqual(len(flows), 1,
                         "There should only be 1 default table 0 flow")

        self._s1ap_wrapper.configUEDevice(1)
        req = self._s1ap_wrapper.ue_req

        print("Running End to End attach for UE id ", req.ue_id)
        self._s1ap_wrapper._s1_util.attach(
            req.ue_id, s1ap_types.tfwCmd.UE_END_TO_END_ATTACH_REQUEST,
            s1ap_types.tfwCmd.UE_ATTACH_ACCEPT_IND,
            s1ap_types.ueAttachAccept_t)

        self._s1ap_wrapper._s1_util.receive_emm_info()

        # UPLINK
        print("Checking for uplink flow")
        # try at least 5 times before failing as gateway
        # might take some time to install the flows in ovs
        for i in range(MAX_NUM_RETRIES):
            print("Get uplink flows: attempt ", i)
            uplink_flows = get_flows(datapath, {
                "table_id": self.SPGW_TABLE,
                "match": {
                    "in_port": self.GTP_PORT
                }
            })
            if len(uplink_flows) > 0:
                break
            time.sleep(5)  # sleep for 5 seconds before retrying

        self.assertEqual(len(uplink_flows), 1, "Uplink flow missing for UE")
        self.assertIsNotNone(uplink_flows[0]["match"]["tunnel_id"],
                             "Uplink flow missing tunnel id match")
        self.check_imsi_metadata(uplink_flows[0], req)

        # DOWNLINK
        print("Checking for downlink flow")
        ue_ip = str(self._s1ap_wrapper._s1_util.get_ip(req.ue_id))
        # Ryu can't match on ipv4_dst, so match on uplink in port
        # try at least 5 times before failing as gateway
        # might take some time to install the flows in ovs
        for i in range(MAX_NUM_RETRIES):
            print("Get downlink flows: attempt ", i)
            downlink_flows = get_flows(
                datapath, {
                    "table_id": self.SPGW_TABLE,
                    "match": {
                        "nw_dst": ue_ip,
                        "eth_type": 2048,
                        "in_port": self.LOCAL_PORT
                    }
                })
            if len(downlink_flows) > 0:
                break
            time.sleep(5)  # sleep for 5 seconds before retrying

        self.assertEqual(len(downlink_flows), 1,
                         "Downlink flow missing for UE")
        self.assertEqual(downlink_flows[0]["match"]["ipv4_dst"], ue_ip,
                         "UE IP match missing from downlink flow")

        actions = downlink_flows[0]["instructions"][0]["actions"]
        has_tunnel_action = any(action for action in actions
                                if action["field"] == "tunnel_id"
                                and action["type"] == "SET_FIELD")
        self.assertTrue(has_tunnel_action,
                        "Downlink flow missing set tunnel action")
        self.check_imsi_metadata(downlink_flows[0], req)

        print("Running UE detach for UE id ", req.ue_id)
        # Now detach the UE
        self._s1ap_wrapper.s1_util.detach(
            req.ue_id, s1ap_types.ueDetachType_t.UE_NORMAL_DETACH.value, True)

        print("Checking that uplink/downlink flows were deleted")
        flows = get_flows(datapath, {
            "table_id": self.SPGW_TABLE,
            "priority": 0
        })
        self.assertEqual(len(flows), 1,
                         "There should only be 1 default table 0 flow")
示例#10
0
    def test_attach_detach_multiple_rar_tcp_data(self):
        """ attach + send two ReAuth Reqs to session manager with a"""
        """ single UE + send TCP data + detach"""

        """ Verify that the data is sent on 2nd dedicated bearer as it has"""
        """ matching PFs and higher priority"""
        num_ues = 1
        detach_type = [
            s1ap_types.ueDetachType_t.UE_NORMAL_DETACH.value,
            s1ap_types.ueDetachType_t.UE_SWITCHOFF_DETACH.value,
        ]
        wait_for_s1 = [True, False]
        self._s1ap_wrapper.configUEDevice(num_ues)
        datapath = get_datapath()
        MAX_NUM_RETRIES = 5
        gtp_br_util = GTPBridgeUtils()
        GTP_PORT = gtp_br_util.get_gtp_port_no()

        for i in range(num_ues):
            req = self._s1ap_wrapper.ue_req
            print(
                "********************** Running End to End attach for ",
                "UE id ",
                req.ue_id,
            )
            # Now actually complete the attach
            attach = self._s1ap_wrapper._s1_util.attach(
                req.ue_id,
                s1ap_types.tfwCmd.UE_END_TO_END_ATTACH_REQUEST,
                s1ap_types.tfwCmd.UE_ATTACH_ACCEPT_IND,
                s1ap_types.ueAttachAccept_t,
            )

            # Wait on EMM Information from MME
            self._s1ap_wrapper._s1_util.receive_emm_info()

            # UL Flow description #1
            ulFlow1 = {
                "ipv4_dst": "192.168.129.42",  # IPv4 destination address
                "tcp_dst_port": 5002,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # UL Flow description #2
            ulFlow2 = {
                "ipv4_dst": "192.168.129.42",  # IPv4 destination address
                "tcp_dst_port": 5001,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # UL Flow description #3
            ulFlow3 = {
                "ipv4_dst": "192.168.129.64",  # IPv4 destination address
                "tcp_dst_port": 5003,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # UL Flow description #4
            ulFlow4 = {
                "ipv4_dst": "192.168.129.42",  # IPv4 destination address
                "tcp_dst_port": 5001,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # DL Flow description #1
            dlFlow1 = {
                "ipv4_src": "192.168.129.42",  # IPv4 source address
                "tcp_src_port": 5001,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # DL Flow description #2
            dlFlow2 = {
                "ipv4_src": "192.168.129.64",  # IPv4 source address
                "tcp_src_port": 5002,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # DL Flow description #3
            dlFlow3 = {
                "ipv4_src": "192.168.129.64",  # IPv4 source address
                "tcp_src_port": 5003,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # DL Flow description #4
            dlFlow4 = {
                "ipv4_src": "192.168.129.42",  # IPv4 source address
                "tcp_src_port": 5001,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # Flow lists to be configured
            flow_list1 = [
                ulFlow1,
                ulFlow2,
                ulFlow3,
                dlFlow1,
                dlFlow2,
                dlFlow3,
            ]
            flow_list2 = [
                ulFlow4,
                dlFlow4,
            ]
            # QoS
            qos1 = {
                "qci": 5,  # qci value [1 to 9]
                "priority": 5,  # Range [0-255]
                "max_req_bw_ul": 10000000,  # MAX bw Uplink
                "max_req_bw_dl": 15000000,  # MAX bw Downlink
                "gbr_ul": 1000000,  # GBR Uplink
                "gbr_dl": 2000000,  # GBR Downlink
                "arp_prio": 15,  # ARP priority
                "pre_cap": 1,  # pre-emption capability
                "pre_vul": 1,  # pre-emption vulnerability
            }
            qos2 = {
                "qci": 1,  # qci value [1 to 9]
                "priority": 1,  # Range [0-255]
                "max_req_bw_ul": 10000000,  # MAX bw Uplink
                "max_req_bw_dl": 15000000,  # MAX bw Downlink
                "gbr_ul": 1000000,  # GBR Uplink
                "gbr_dl": 2000000,  # GBR Downlink
                "arp_prio": 1,  # ARP priority
                "pre_cap": 1,  # pre-emption capability
                "pre_vul": 1,  # pre-emption vulnerability
            }

            policy_id1 = "ims-voice"
            policy_id2 = "internet"

            print("Sleeping for 5 seconds")
            time.sleep(5)
            print(
                "********************** Sending RAR for IMSI",
                "".join([str(i) for i in req.imsi]),
            )
            self._sessionManager_util.send_ReAuthRequest(
                "IMSI" + "".join([str(i) for i in req.imsi]),
                policy_id1,
                flow_list1,
                qos1,
            )

            # Receive Activate dedicated bearer request
            response = self._s1ap_wrapper.s1_util.get_response()
            self.assertEqual(
                response.msg_type, s1ap_types.tfwCmd.UE_ACT_DED_BER_REQ.value
            )
            act_ded_ber_ctxt_req1 = response.cast(
                s1ap_types.UeActDedBearCtxtReq_t
            )

            print("Sleeping for 5 seconds")
            time.sleep(5)
            # Send Activate dedicated bearer accept
            self._s1ap_wrapper.sendActDedicatedBearerAccept(
                req.ue_id, act_ded_ber_ctxt_req1.bearerId
            )

            print(
                "********************** Sending 2nd RAR for IMSI",
                "".join([str(i) for i in req.imsi]),
            )

            self._sessionManager_util.send_ReAuthRequest(
                "IMSI" + "".join([str(i) for i in req.imsi]),
                policy_id2,
                flow_list2,
                qos2,
            )

            # Receive Activate dedicated bearer request
            response = self._s1ap_wrapper.s1_util.get_response()
            self.assertEqual(
                response.msg_type, s1ap_types.tfwCmd.UE_ACT_DED_BER_REQ.value
            )
            act_ded_ber_ctxt_req2 = response.cast(
                s1ap_types.UeActDedBearCtxtReq_t
            )

            print("Sleeping for 5 seconds")
            time.sleep(5)
            # Send Activate dedicated bearer accept
            self._s1ap_wrapper.sendActDedicatedBearerAccept(
                req.ue_id, act_ded_ber_ctxt_req2.bearerId
            )

            # Check if UL and DL OVS flows are created
            # UPLINK
            print("Checking for uplink flow")
            # try at least 5 times before failing as gateway
            # might take some time to install the flows in ovs
            for i in range(MAX_NUM_RETRIES):
                print("Get uplink flows: attempt ", i)
                uplink_flows = get_flows(
                    datapath,
                    {
                        "table_id": self.SPGW_TABLE,
                        "match": {"in_port": GTP_PORT},
                    },
                )
                if len(uplink_flows) > 2:
                    break
                time.sleep(5)  # sleep for 5 seconds before retrying

            assert len(uplink_flows) > 2, "Uplink flow missing for UE"
            self.assertIsNotNone(
                uplink_flows[0]["match"]["tunnel_id"],
                "Uplink flow missing tunnel id match",
            )

            # DOWNLINK
            print("Checking for downlink flow")
            ue_ip = str(self._s1ap_wrapper._s1_util.get_ip(req.ue_id))
            # try at least 5 times before failing as gateway
            # might take some time to install the flows in ovs
            for i in range(MAX_NUM_RETRIES):
                print("Get downlink flows: attempt ", i)
                downlink_flows = get_flows(
                    datapath,
                    {
                        "table_id": self.SPGW_TABLE,
                        "match": {
                            "nw_dst": ue_ip,
                            "eth_type": 2048,
                            "in_port": self.LOCAL_PORT,
                        },
                    },
                )
                if len(downlink_flows) > 2:
                    break
                time.sleep(5)  # sleep for 5 seconds before retrying

            assert len(downlink_flows) > 2, "Downlink flow missing for UE"
            self.assertEqual(
                downlink_flows[0]["match"]["ipv4_dst"],
                ue_ip,
                "UE IP match missing from downlink flow",
            )

            actions = downlink_flows[0]["instructions"][0]["actions"]
            has_tunnel_action = any(
                action
                for action in actions
                if action["field"] == "tunnel_id"
                and action["type"] == "SET_FIELD"
            )
            self.assertTrue(
                has_tunnel_action, "Downlink flow missing set tunnel action"
            )

            with self._s1ap_wrapper.configUplinkTest(req, duration=1) as test:
                test.verify()

            print("Sleeping for 5 seconds")
            time.sleep(5)

            print(
                "********************** Deleting dedicated bearer for IMSI",
                "".join([str(i) for i in req.imsi]),
            )
            self._spgw_util.delete_bearer(
                "IMSI" + "".join([str(i) for i in req.imsi]),
                attach.esmInfo.epsBearerId,
                act_ded_ber_ctxt_req1.bearerId,
            )

            response = self._s1ap_wrapper.s1_util.get_response()
            self.assertEqual(
                response.msg_type,
                s1ap_types.tfwCmd.UE_DEACTIVATE_BER_REQ.value,
            )

            print("******************* Received deactivate eps bearer context")

            deactv_bearer_req = response.cast(s1ap_types.UeDeActvBearCtxtReq_t)
            self._s1ap_wrapper.sendDeactDedicatedBearerAccept(
                req.ue_id, deactv_bearer_req.bearerId
            )

            print("Sleeping for 5 seconds")
            time.sleep(5)

            print(
                "********************** Running UE detach for UE id ",
                req.ue_id,
            )
            # Now detach the UE
            self._s1ap_wrapper.s1_util.detach(
                req.ue_id, detach_type[i], wait_for_s1[i]
            )

            print("Checking that uplink/downlink flows were deleted")
            flows = get_flows(
                datapath, {"table_id": self.SPGW_TABLE, "priority": 0}
            )
            self.assertEqual(
                len(flows), 2, "There should only be 2 default table 0 flows"
            )
示例#11
0
 def __init__(self, table_id, ovs_ip=LOCALHOST, match=None, cookie=None):
     self._table_id = table_id
     self._datapath = get_datapath(ovs_ip)
     self._ovs_ip = ovs_ip
     self._match = match
     self._cookie = cookie
    def test_attach_detach_rar_tcp_data_with_he(self):
        """ Attach/detach + send ReAuth Req to session manager with a
        single UE along with Header enrichment.
        This test validates that same data test wotks with HE policy
        applied.
        Header enrichment should be as transparent as possible.
        """
        num_ues = 1
        detach_type = [
            s1ap_types.ueDetachType_t.UE_NORMAL_DETACH.value,
            s1ap_types.ueDetachType_t.UE_SWITCHOFF_DETACH.value,
        ]
        wait_for_s1 = [True, False]
        self._s1ap_wrapper.configUEDevice(num_ues)
        datapath = get_datapath()
        MAX_NUM_RETRIES = 5
        gtp_br_util = GTPBridgeUtils()
        GTP_PORT = gtp_br_util.get_gtp_port_no()
        utils = HeaderEnrichmentUtils()

        for i in range(num_ues):
            req = self._s1ap_wrapper.ue_req
            print(
                "********************** Running End to End attach for ",
                "UE id ",
                req.ue_id,
            )
            # Now actually complete the attach
            self._s1ap_wrapper._s1_util.attach(
                req.ue_id,
                s1ap_types.tfwCmd.UE_END_TO_END_ATTACH_REQUEST,
                s1ap_types.tfwCmd.UE_ATTACH_ACCEPT_IND,
                s1ap_types.ueAttachAccept_t,
            )

            # Wait on EMM Information from MME
            self._s1ap_wrapper._s1_util.receive_emm_info()

            # UL Flow description #1
            ulFlow1 = {
                "ipv4_dst": "192.168.129.42",  # IPv4 destination address
                "tcp_dst_port": 5002,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # UL Flow description #2
            ulFlow2 = {
                "ipv4_dst": "192.168.129.42",  # IPv4 destination address
                "tcp_dst_port": 5001,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # UL Flow description #3
            ulFlow3 = {
                "ipv4_dst": "192.168.129.64",  # IPv4 destination address
                "tcp_dst_port": 5003,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # UL Flow description #4
            ulFlow4 = {
                "ipv4_dst": "192.168.129.42",  # IPv4 destination address
                "tcp_dst_port": 5004,  # TCP dest port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.UPLINK,  # Direction
            }

            # DL Flow description #1
            dlFlow1 = {
                "ipv4_src": "192.168.129.42",  # IPv4 source address
                "tcp_src_port": 5001,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # DL Flow description #2
            dlFlow2 = {
                "ipv4_src": "192.168.129.64",  # IPv4 source address
                "tcp_src_port": 5002,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # DL Flow description #3
            dlFlow3 = {
                "ipv4_src": "192.168.129.64",  # IPv4 source address
                "tcp_src_port": 5003,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # DL Flow description #4
            dlFlow4 = {
                "ipv4_src": "192.168.129.42",  # IPv4 source address
                "tcp_src_port": 5004,  # TCP source port
                "ip_proto": FlowMatch.IPPROTO_TCP,  # Protocol Type
                "direction": FlowMatch.DOWNLINK,  # Direction
            }

            # Flow list to be configured
            flow_list = [
                ulFlow1,
                ulFlow2,
                ulFlow3,
                ulFlow4,
                dlFlow1,
                dlFlow2,
                dlFlow3,
                dlFlow4,
            ]

            # QoS
            qos = {
                "qci": 5,  # qci value [1 to 9]
                "priority": 0,  # Range [0-255]
                "max_req_bw_ul": 10000000,  # MAX bw Uplink
                "max_req_bw_dl": 15000000,  # MAX bw Downlink
                "gbr_ul": 1000000,  # GBR Uplink
                "gbr_dl": 2000000,  # GBR Downlink
                "arp_prio": 15,  # ARP priority
                "pre_cap": 1,  # pre-emption capability
                "pre_vul": 1,  # pre-emption vulnerability
            }

            policy_id = "ims-voice"

            print("Sleeping for 5 seconds")
            time.sleep(5)
            imsi = "IMSI" + "".join([str(i) for i in req.imsi])

            print(
                "********************** Sending RAR for ",
                imsi,
            )
            he_domain1 = "192.168.128.1"
            assert utils.he_count_record_of_imsi_to_domain(imsi,
                                                           he_domain1) == 0

            self._sessionManager_util.send_ReAuthRequest(
                "IMSI" + "".join([str(i) for i in req.imsi]),
                policy_id,
                flow_list,
                qos,
                he_urls=HeaderEnrichment(urls=[he_domain1]),
            )

            # Receive Activate dedicated bearer request
            response = self._s1ap_wrapper.s1_util.get_response()
            self.assertEqual(
                response.msg_type,
                s1ap_types.tfwCmd.UE_ACT_DED_BER_REQ.value,
            )
            act_ded_ber_ctxt_req = response.cast(
                s1ap_types.UeActDedBearCtxtReq_t, )

            print("Sleeping for 5 seconds")
            time.sleep(5)
            # Send Activate dedicated bearer accept
            self._s1ap_wrapper.sendActDedicatedBearerAccept(
                req.ue_id,
                act_ded_ber_ctxt_req.bearerId,
            )

            # Check if UL and DL OVS flows are created
            # UPLINK
            print("Checking for uplink flow")
            # try at least 5 times before failing as gateway
            # might take some time to install the flows in ovs
            for i in range(MAX_NUM_RETRIES):
                print("Get uplink flows: attempt ", i)
                uplink_flows = get_flows(
                    datapath,
                    {
                        "table_id": self.SPGW_TABLE,
                        "match": {
                            "in_port": GTP_PORT
                        },
                    },
                )
                if len(uplink_flows) > 1:
                    break
                time.sleep(5)  # sleep for 5 seconds before retrying

            assert len(uplink_flows) > 1, "Uplink flow missing for UE"
            self.assertIsNotNone(
                uplink_flows[0]["match"]["tunnel_id"],
                "Uplink flow missing tunnel id match",
            )

            # DOWNLINK
            print("Checking for downlink flow")
            ue_ip = str(self._s1ap_wrapper._s1_util.get_ip(req.ue_id))
            # try at least 5 times before failing as gateway
            # might take some time to install the flows in ovs
            for i in range(MAX_NUM_RETRIES):
                print("Get downlink flows: attempt ", i)
                downlink_flows = get_flows(
                    datapath,
                    {
                        "table_id": self.SPGW_TABLE,
                        "match": {
                            "nw_dst": ue_ip,
                            "eth_type": 2048,
                            "in_port": self.LOCAL_PORT,
                        },
                    },
                )
                if len(downlink_flows) > 1:
                    break
                time.sleep(5)  # sleep for 5 seconds before retrying

            assert len(downlink_flows) > 1, "Downlink flow missing for UE"
            self.assertEqual(
                downlink_flows[0]["match"]["ipv4_dst"],
                ue_ip,
                "UE IP match missing from downlink flow",
            )

            actions = downlink_flows[0]["instructions"][0]["actions"]
            has_tunnel_action = any(action for action in actions
                                    if action["field"] == "tunnel_id"
                                    and action["type"] == "SET_FIELD")
            self.assertTrue(
                has_tunnel_action,
                "Downlink flow missing set tunnel action",
            )

            print("Sleeping for 5 seconds")
            time.sleep(5)
            with self._s1ap_wrapper.configUplinkTest(req, duration=1) as test:
                test.verify()
            assert utils.he_count_record_of_imsi_to_domain(imsi,
                                                           he_domain1) == 1

            print(
                "********************** Deleting dedicated bearer for IMSI",
                "".join([str(i) for i in req.imsi]),
            )
            self._spgw_util.delete_bearer(
                "IMSI" + "".join([str(i) for i in req.imsi]),
                5,
                6,
            )

            response = self._s1ap_wrapper.s1_util.get_response()
            self.assertEqual(
                response.msg_type,
                s1ap_types.tfwCmd.UE_DEACTIVATE_BER_REQ.value,
            )

            print("******************* Received deactivate eps bearer context")

            deactv_bearer_req = response.cast(s1ap_types.UeDeActvBearCtxtReq_t)
            self._s1ap_wrapper.sendDeactDedicatedBearerAccept(
                req.ue_id,
                deactv_bearer_req.bearerId,
            )

            print("Sleeping for 5 seconds")
            time.sleep(5)

            print(
                "********************** Running UE detach for UE id ",
                req.ue_id,
            )
            # Now detach the UE
            self._s1ap_wrapper.s1_util.detach(
                req.ue_id,
                detach_type[i],
                wait_for_s1[i],
            )

            time.sleep(20)
            assert utils.he_count_record_of_imsi_to_domain(imsi,
                                                           he_domain1) == 0

        # Verify that all UL/DL flows are deleted
        self._s1ap_wrapper.s1_util.verify_flow_rules_deletion()