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")
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')
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)
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)
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()
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
def __init__(self, requests, ovs_ip=LOCALHOST): self._requests = requests self._ovs_ip = ovs_ip self._datapath = get_datapath(ovs_ip)
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()
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")
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" )
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()