def test_meter_stats(self): """ Test metering stats by sending uplink and downlink packets from 2 subscribers and making sure the correct statistics are sent to the cloud """ # Set up subscribers sub1 = SubContextConfig('IMSI001010000000013', '192.168.128.74', self._tbl_num) sub2 = SubContextConfig('IMSI001010000000014', '192.168.128.75', self._tbl_num) isolator1 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub1) .build_requests(), self.testing_controller, ) isolator2 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub2) .build_requests(), self.testing_controller, ) # Set up packets pkt_sender = ScapyPacketInjector(self.BRIDGE) pkt_count = 4 # send each packet 4 times # sub1: 2 uplink pkts, 1 downlink # sub2: 1 uplink pkt packets = [ self._make_default_pkt('45.10.0.1', sub1.ip), self._make_default_pkt('45.10.0.2', sub1.ip), self._make_default_pkt(sub1.ip, '45.10.0.1'), self._make_default_pkt('45.10.0.3', sub2.ip), ] pkt_size = len(packets[0]) # These packets are sent at the start to install the meter flows initial_packets = [ self._make_default_pkt('45.10.0.2', sub1.ip), self._make_default_pkt('45.10.0.3', sub2.ip), ] target_usage = { # sub1: 2 uplink * 4 packets each = 8 # 1 downlink * 4 packets each = 4 sub1.imsi: _create_usage_record(8, 4, pkt_size), # sub2: 1 uplink * 4 packets each = 4 sub2.imsi: _create_usage_record(4, 0, pkt_size), } # Send packets through pipeline and wait with isolator1, isolator2: for pkt in initial_packets: pkt_sender.send(pkt, 1) wait_after_send(self.testing_controller) for pkt in packets: pkt_sender.send(pkt, pkt_count) wait_after_send(self.testing_controller) wait_for_meter_stats(self.stats_controller, target_usage)
def test_ocs_failure(self): """ Test that when the OCS fails to respond to an update request, the service is cut off until the update can be completed """ sub1 = SubContextConfig('IMSI001010000088888', '192.168.128.74', default_ambr_config, 4) quota = 1024 self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[create_update_response(sub1.imsi, 1, quota)], static_rules=[session_manager_pb2.StaticRuleInstall( rule_id="simple_match" )], ), ) update_complete = hub.Queue() self.test_util.controller.mock_update_session = Mock( side_effect=get_standard_update_response( update_complete, None, quota, success=False), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.assertEqual(self.test_util.controller.mock_create_session.call_count, 1) packets = get_packets_for_flows( sub1, self.test_util.static_rules["simple_match"].flow_list) packet_count = int(quota / len(packets[0])) + 1 sender = self.test_util.get_packet_sender([sub1], packets, packet_count) # assert after session init, data can flow self.assertGreater(self.test_util.thread.run_in_greenthread(sender), 0) # wait for failed update self.assertIsNotNone(get_from_queue(update_complete)) hub.sleep(2) # assert that no data can be sent anymore self.assertEqual(self.test_util.thread.run_in_greenthread(sender), 0) self.test_util.controller.mock_update_session = Mock( side_effect=get_standard_update_response( update_complete, None, quota, success=True), ) # wait for second update cycle to reactivate hub.sleep(4) self.assertGreater(self.test_util.thread.run_in_greenthread(sender), 0) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual(self.test_util.controller.mock_terminate_session.call_count, 1)
def _setup_subscribers_ipv6(self): return SubContextConfig( 'IMSI001010000000013', 'ab42::74', default_ambr_config, self._tbl_num, )
def _setup_subscribers(self): return SubContextConfig( 'IMSI001010000000013', '192.168.128.74', default_ambr_config, self._tbl_num, )
def send_create_session(client, args): sub1 = SubContextConfig('IMSI' + args.imsi, '192.168.128.74', 4) try: create_account_in_PCRF(args.imsi) except grpc.RpcError as e: print("gRPC failed with %s: %s" % (e.code(), e.details())) try: create_account_in_OCS(args.imsi) except grpc.RpcError as e: print("gRPC failed with %s: %s" % (e.code(), e.details())) req = LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ) print("Sending LocalCreateSessionRequest with following fields:\n %s" % req) try: client.CreateSession(req) except grpc.RpcError as e: print("gRPC failed with %s: %s" % (e.code(), e.details())) req = SubscriberID(id=sub1.imsi) print("Sending EndSession with following fields:\n %s" % req) try: client.EndSession(req) except grpc.RpcError as e: print("gRPC failed with %s: %s" % (e.code(), e.details()))
def test_conntrack(self): """ Test that conntrack rules are properly setup Verifies that 3 new connections are detected (2 tcp, 1 udp) """ sub_ip = '145.254.160.237' # extracted from pcap don't change sub = SubContextConfig( 'IMSI001010000000013', sub_ip, default_ambr_config, self._tbl_num, ) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub).build_requests(), self.testing_controller, ) pkt_sender = ScapyPacketInjector(self.BRIDGE) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, include_stats=False, ) current_path = \ str(pathlib.Path(__file__).parent.absolute()) with isolator, snapshot_verifier: pkt_sender.send_pcap(current_path + "/pcaps/http_download.cap")
def test_gre_learn(self): """ Test that uplink packet hits the learn rule and a new flow is created in the scratch table(snapshot is checked) """ # Set up subscribers sub = SubContextConfig('IMSI001010000000013', '192.168.128.74', self._tbl_num) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub).build_requests(), self.testing_controller, ) # Set up packets pkt_sender = ScapyPacketInjector(self.BRIDGE) pkt = IPPacketBuilder() \ .set_ip_layer(self.INBOUND_TEST_IP, sub.ip) \ .set_ether_layer(self.MAC_DEST, "01:02:03:04:05:06") \ .build() with isolator: pkt_sender.send(pkt) assert_bridge_snapshot_match(self, self.BRIDGE, self.service_manager)
def test_basic_init(self): """ Initiate subscriber, return 1 static policy with monitoring key, send traffic to match the policy, verify monitoring update is sent, terminate subscriber """ sub1 = SubContextConfig('IMSI001010000088888', '192.168.128.74', default_ambr_config, 4) quota = 1024 # bytes self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[], static_rules=[ session_manager_pb2.StaticRuleInstall( rule_id="monitor_rule", ), ], dynamic_rules=[], usage_monitors=[ create_monitor_response( sub1.imsi, "mkey1", quota, session_manager_pb2.PCC_RULE_LEVEL, ), ], ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) monitor_complete = hub.Queue() self.test_util.controller.mock_update_session = Mock( side_effect=get_standard_update_response( None, monitor_complete, quota, ), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.assertEqual(self.test_util.controller.mock_create_session.call_count, 1) packets = get_packets_for_flows( sub1, self.test_util.static_rules["monitor_rule"].flow_list, ) packet_count = int(quota / len(packets[0])) + 1 self.test_util.thread.run_in_greenthread( self.test_util.get_packet_sender([sub1], packets, packet_count), ) self.assertIsNotNone(get_from_queue(monitor_complete)) self.assertEqual(self.test_util.controller.mock_update_session.call_count, 1) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual(self.test_util.controller.mock_terminate_session.call_count, 1)
def test_no_match(self): """ No match test, checks that packets are not matched when the there is no match to the ip and direction in the blacklist. Assert: Both packets are not matched Ip match flows are added """ # Set up subscribers sub = SubContextConfig('IMSI001010000000013', '192.168.128.74', self._tbl_num) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub).build_requests(), self.testing_controller, ) # Set up packets. The directions of the packets are opposite of the # installed match flow, so there should not matches. pkt_sender = ScapyPacketInjector(self.BRIDGE) packets = [ self._build_default_ip_packet(self.OUTBOUND_TEST_IP, sub.ip), self._build_default_ip_packet(sub.ip, self.INBOUND_TEST_IP), ] # Check if these flows were added (queries should return flows) outbound_flow_queries = [ FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT, ipv4_dst=self.INBOUND_TEST_IP)), FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN, ipv4_src=self.OUTBOUND_TEST_IP)), ] # =========================== Verification =========================== # packets are not matched, ip match flows installed flow_verifier = FlowVerifier( [ FlowTest( FlowQuery(self._tbl_num, self.testing_controller), 2), ] + [FlowTest(query, 0, flow_count=1) for query in outbound_flow_queries], lambda: wait_after_send( self.testing_controller) ) with isolator, flow_verifier: for packet in packets: pkt_sender.send(packet) flow_verifier.verify() assert_bridge_snapshot_match(self, self.BRIDGE, self.service_manager)
def test_inbound_ip_match(self): """ Inbound ip match test, checks that packets are properly matched when the inbound traffic matches an ip in the blocklist. Assert: Both packets are matched Ip match flows are added """ # Set up subscribers sub = SubContextConfig('IMSI001010000000013', '192.168.128.74', default_ambr_config, self._tbl_num) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub).build_requests(), self.testing_controller, ) # Set up packets pkt_sender = ScapyPacketInjector(self.BRIDGE) packets = [ self._build_default_ip_packet(self.INBOUND_TEST_IP, sub.ip), self._build_default_ip_packet(self.BOTH_DIR_TEST_IP, sub.ip), ] # Check if these flows were added (queries should return flows) inbound_flow_queries = [ FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT, ipv4_dst=self.INBOUND_TEST_IP)), FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT, ipv4_dst=self.BOTH_DIR_TEST_IP)), ] # =========================== Verification =========================== # packets matched, ip match flows installed flow_verifier = FlowVerifier( [ FlowTest( FlowQuery(self._tbl_num, self.testing_controller), 2), ] + [FlowTest(query, 1, flow_count=1) for query in inbound_flow_queries], lambda: wait_after_send( self.testing_controller) ) with isolator, flow_verifier: for packet in packets: pkt_sender.send(packet) flow_verifier.verify() assert_bridge_snapshot_match(self, self.BRIDGE, self.service_manager)
def test_rules_with_failed_credit(self): """ Test that when a session is initialized but the OCS either errored out or returned 0 GSUs, data is not allowed to flow """ sub1 = SubContextConfig('IMSI001010000088888', '192.168.128.74', default_ambr_config, 4) rule2 = create_uplink_rule("rule2", 2, '46.10.0.1') rule3 = create_uplink_rule("rule3", 3, '47.10.0.1') self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[ # failed update create_update_response(sub1.imsi, 1, 0, success=False), # successful update, no credit create_update_response(sub1.imsi, 1, 0, success=True), ], static_rules=[session_manager_pb2.StaticRuleInstall( rule_id="simple_match" )], # no credit for RG 1 dynamic_rules=[ session_manager_pb2.DynamicRuleInstall( policy_rule=rule2 ), session_manager_pb2.DynamicRuleInstall( policy_rule=rule3 ) ], ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.assertEqual(self.test_util.controller.mock_create_session.call_count, 1) flows = [rule.flow_list[0] for rule in [rule2, rule3]] packets = get_packets_for_flows(sub1, flows) pkt_diff = self.test_util.thread.run_in_greenthread( self.test_util.get_packet_sender([sub1], packets, 1), ) self.assertEqual(pkt_diff, 0) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual(self.test_util.controller.mock_terminate_session.call_count, 1)
def test_blocking_ip_match(self): """ Inbound ip match test, checks that packets are properly matched when the inbound traffic matches an ip in the blocklist. Assert: Both packets are matched Ip match flows are added """ # Set up subscribers sub = SubContextConfig( 'IMSI001010000000013', '192.168.128.74', default_ambr_config, self._tbl_num, ) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub).build_requests(), self.testing_controller, ) # Set up packets pkt_sender = ScapyPacketInjector(self.BRIDGE) packets = [ _build_default_ip_packet(self.MAC_DEST, self.OUTBOUND_TEST_IP1, sub.ip), _build_default_ip_packet(self.MAC_DEST, self.OUTBOUND_TEST_IP2, sub.ip), _build_default_ip_packet(self.MAC_DEST, self.BOTH_DIR_TEST_IP, sub.ip), ] with isolator: for packet in packets: pkt_sender.send(packet) assert_bridge_snapshot_match( self, self.BRIDGE, self.service_manager, )
def test_rule_with_no_credit(self): """ Test that when a rule is returned that requires OCS tracking but has no credit, data is not allowed to pass """ sub1 = SubContextConfig('IMSI001010000088888', '192.168.128.74', default_ambr_config, 4) self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( static_rules=[ session_manager_pb2.StaticRuleInstall( rule_id="simple_match", ), ], # no credit for RG 1 ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.assertEqual( self.test_util.controller.mock_create_session.call_count, 1) packets = get_packets_for_flows( sub1, self.test_util.static_rules["simple_match"].flow_list, ) pkt_diff = self.test_util.thread.run_in_greenthread( self.test_util.get_packet_sender([sub1], packets, 1), ) self.assertEqual(pkt_diff, 0) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual( self.test_util.controller.mock_terminate_session.call_count, 1)
def test_out_of_credit(self): """ Initiate subscriber, return 1 static policy, send traffic to match the policy, verify update is sent, return final credits, use up final credits, ensure that no traffic can be sent """ sub1 = SubContextConfig('IMSI001010000088888', '192.168.128.74', 4) quota = 1024 # bytes self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[ session_manager_pb2.CreditUpdateResponse( success=True, sid=sub1.imsi, charging_key=1, credit=session_manager_pb2.ChargingCredit( granted_units=session_manager_pb2.GrantedUnits( total=session_manager_pb2.CreditUnit( is_valid=True, volume=quota, ), ), ), ) ], static_rules=[ session_manager_pb2.StaticRuleInstall( rule_id="simple_match") ], dynamic_rules=[], usage_monitors=[], ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) update_complete = hub.Queue() self.test_util.controller.mock_update_session = Mock( side_effect=get_standard_update_response(update_complete, None, quota, is_final=True), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.assertEqual( self.test_util.controller.mock_create_session.call_count, 1) packets = get_packets_for_flows( sub1, self.test_util.static_rules["simple_match"].flow_list) packet_count = int(quota / len(packets[0])) + 1 send_packets = self.test_util.get_packet_sender([sub1], packets, packet_count) self.test_util.thread.run_in_greenthread(send_packets) self.assertIsNotNone(get_from_queue(update_complete)) self.assertEqual( self.test_util.controller.mock_update_session.call_count, 1) # use up last credits self.test_util.thread.run_in_greenthread(send_packets) hub.sleep(3) # wait for sessiond to terminate rule after update pkt_diff = self.test_util.thread.run_in_greenthread(send_packets) self.assertEqual(pkt_diff, 0) self.test_util.proxy_responder.ChargingReAuth( session_manager_pb2.ChargingReAuthRequest( charging_key=1, sid=sub1.imsi, ), ) get_from_queue(update_complete) self.assertEqual( self.test_util.controller.mock_update_session.call_count, 2) # wait for 1 update to trigger credit request, another to trigger # rule activation # TODO Add future to track when flows are added/deleted hub.sleep(5) pkt_diff = self.test_util.thread.run_in_greenthread(send_packets) self.assertGreater(pkt_diff, 0) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual( self.test_util.controller.mock_terminate_session.call_count, 1)
def test_mixed_monitors_and_updates(self): """ Test a mix of usage monitors, session monitors, and charging credits to PCRF and OCS. """ sub1 = SubContextConfig('IMSI001010000088888', '192.168.128.74', 4) quota = 1024 # bytes pcrf_rule = create_uplink_rule("pcrf_rule", 0, '46.10.0.1', m_key="key1", tracking=PolicyRule.ONLY_PCRF) ocs_rule = create_uplink_rule("ocs_rule", 1, '47.10.0.1', tracking=PolicyRule.ONLY_OCS) both_rule = create_uplink_rule("both_rule", 2, '48.10.0.1', m_key="key2", tracking=PolicyRule.OCS_AND_PCRF) self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[ create_update_response("", 1, quota), create_update_response("", 2, quota), ], dynamic_rules=[ session_manager_pb2.DynamicRuleInstall( policy_rule=pcrf_rule, ), session_manager_pb2.DynamicRuleInstall( policy_rule=ocs_rule, ), session_manager_pb2.DynamicRuleInstall( policy_rule=both_rule, ), ], usage_monitors=[ create_monitor_response( sub1.imsi, "key1", quota, session_manager_pb2.PCC_RULE_LEVEL, ), create_monitor_response( sub1.imsi, "key2", quota, session_manager_pb2.PCC_RULE_LEVEL, ), create_monitor_response( sub1.imsi, "key3", quota, session_manager_pb2.SESSION_LEVEL, ), ], ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) charging_complete = hub.Queue() monitor_complete = hub.Queue() self.test_util.controller.mock_update_session = Mock( side_effect=get_standard_update_response( charging_complete, monitor_complete, quota), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.assertEqual(self.test_util.controller.mock_create_session.call_count, 1) flows = [rule.flow_list[0] for rule in [pcrf_rule, ocs_rule, both_rule]] packets = get_packets_for_flows(sub1, flows) packet_count = int(quota / len(packets[0])) + 1 self.test_util.thread.run_in_greenthread( self.test_util.get_packet_sender([sub1], packets, packet_count), ) # Wait for responses for keys 1 and 2 (ocs_rule and both_rule) charging_keys = {1, 2} for _ in range(len(charging_keys)): update = get_from_queue(charging_complete) self.assertTrue(update.usage.charging_key in charging_keys) charging_keys.remove(update.usage.charging_key) # Wait for responses for mkeys key1 (pcrf_rule), key2 (both_rule), # key3 (session rule) monitoring_keys = ["key1", "key2", "key3"] for _ in range(len(monitoring_keys)): monitor = get_from_queue(monitor_complete) self.assertTrue(monitor.update.monitoring_key in monitoring_keys) monitoring_keys.remove(monitor.update.monitoring_key) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual(self.test_util.controller.mock_terminate_session.call_count, 1)
def test_meter_stats(self): """ Test metering stats by sending uplink and downlink packets from 2 subscribers and making sure the correct statistics are sent to the cloud """ # Set up subscribers sub1 = SubContextConfig('IMSI001010000000013', '192.168.128.74', self._tbl_num) sub2 = SubContextConfig('IMSI001010000000014', '192.168.128.75', self._tbl_num) isolator1 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub1).build_requests(), self.testing_controller, ) isolator2 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub2).build_requests(), self.testing_controller, ) # Set up packets pkt_sender = ScapyPacketInjector(self.BRIDGE) pkt_count = 4 # send each packet 4 times # sub1: 2 uplink pkts, 1 downlink # sub2: 1 uplink pkt packets = [ self._make_default_pkt('45.10.0.1', sub1.ip), self._make_default_pkt('45.10.0.2', sub1.ip), self._make_default_pkt(sub1.ip, '45.10.0.1'), self._make_default_pkt('45.10.0.3', sub2.ip), ] pkt_size = len(packets[0]) # Send packets through pipeline and wait with isolator1, isolator2: for pkt in packets: pkt_sender.send(pkt, pkt_count) wait_after_send(self.testing_controller) hub.sleep(3) # manually run stats update for _, datapath in self.stats_controller.dpset.get_all(): self.stats_controller._poll_stats(datapath) # retrieve the latest statistics stats_queue = hub.Queue() def mock_sync_stats(*args, **kwargs): stats_queue.put(args[0]) self.stats_controller._sync_stats = MagicMock( side_effect=mock_sync_stats, ) stats_dict = stats_queue.get(block=True, timeout=5) self.assertTrue(sub1.imsi in stats_dict) self.assertTrue(sub2.imsi in stats_dict) # sub1: 2 uplink * 4 packets each - 1 packet in = 3 # 1 downlink * 4 packets each - 1 packet in = 7 self._assert_stats_match(stats_dict[sub1.imsi], 7, 3, pkt_size) # sub2: 1 uplink * 4 packets each - 1 packet in = 3 self._assert_stats_match(stats_dict[sub2.imsi], 3, 0, pkt_size)
def test_process_deleted_subscriber(self): """ With usage polling on, send packets to install metering flows and delete one of them by removing the subscriber from the subscriber ip table. Verifies that the metering flows for the subscriber is deleted after the correct usage is reported. """ # Set up subscribers sub1 = SubContextConfig('IMSI001010000000013', '192.168.128.74', self._tbl_num) sub2 = SubContextConfig('IMSI001010000000014', '192.168.128.75', self._tbl_num) isolator1 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub1).build_requests(), self.testing_controller, ) isolator2 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub2).build_requests(), self.testing_controller, ) # Set up packets pkt_sender = ScapyPacketInjector(self.BRIDGE) packets = [ _make_default_pkt(self.MAC_DEST, '45.10.0.1', sub1.ip), _make_default_pkt(self.MAC_DEST, '45.10.0.3', sub2.ip), ] # Initialize subscriber list in subscriber controller. subscriber_ip_table = SubscriberIPTable() subscriber_ip_table.entries.extend([ SubscriberIPTableEntry(sid=SubscriberID(id='IMSI001010000000013')), SubscriberIPTableEntry(sid=SubscriberID(id='IMSI001010000000014')), ]) fut = Future() fut.set_result(subscriber_ip_table) self.subscriber_controller._poll_subscriber_list_done(fut) # Verify that after the poll, flows for subscriber 1 and 2 are # installed and the second pair of packets sent are matched. sub1_query = RyuDirectFlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch(imsi=encode_imsi('IMSI001010000000013'))) sub2_query = RyuDirectFlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch(imsi=encode_imsi('IMSI001010000000014'))) flow_verifier = FlowVerifier([ FlowTest(sub1_query, 1, 2), FlowTest(sub2_query, 1, 2), ], lambda: None) # Send packets through pipeline and wait. with isolator1, isolator2, flow_verifier: # Send packets to create the metering flows. Note that these # packets will not be matched because the test setup does not # support outputting to port. for pkt in packets: pkt_sender.send(pkt) wait_after_send(self.testing_controller) # Update the subscriber list to delete subscriber 2. subscriber_ip_table = SubscriberIPTable() subscriber_ip_table.entries.extend([ SubscriberIPTableEntry(sid=SubscriberID( id='IMSI001010000000013')), ]) fut = Future() fut.set_result(subscriber_ip_table) self.subscriber_controller._poll_subscriber_list_done(fut) # Send another pair of packets which will be matched. for pkt in packets: pkt_sender.send(pkt) wait_after_send(self.testing_controller) # Temporarily mock out _handle_flow_stats because flow_verifier # sends a stats request to the meter table, which will trigger # the deletion prematurely. handle_flow_stats = self.subscriber_controller._handle_flow_stats self.subscriber_controller._handle_flow_stats = MagicMock() flow_verifier.verify() self.subscriber_controller._handle_flow_stats = handle_flow_stats # Verify that after the usage is reported, the flows for subscriber 2 # are deleted. sub1_record = UsageRecord() sub1_record.bytes_tx = len(packets[0]) sub2_record = UsageRecord() sub2_record.bytes_tx = len(packets[1]) target_usage = { 'IMSI001010000000013': sub1_record, 'IMSI001010000000014': sub2_record, } flow_verifier = FlowVerifier([ FlowTest(sub1_query, 0, 2), FlowTest(sub2_query, 0, 0), ], lambda: wait_for_meter_stats(self.stats_controller, target_usage)) with flow_verifier: self._poll_stats() flow_verifier.verify()
def test_process_deleted_subscriber(self): """ With usage polling off, send packets to install metering flows and delete one of them by removing the subscriber from the subscriber ip table. Verifies that the metering flows for the subscriber is deleted when the subscriber is deleted. """ # Set up subscribers sub1 = SubContextConfig('IMSI001010000000013', '192.168.128.74', self._tbl_num) sub2 = SubContextConfig('IMSI001010000000014', '192.168.128.75', self._tbl_num) isolator1 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub1).build_requests(), self.testing_controller, ) isolator2 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub2).build_requests(), self.testing_controller, ) # Set up packets pkt_sender = ScapyPacketInjector(self.BRIDGE) packets = [ _make_default_pkt(self.MAC_DEST, '45.10.0.1', sub1.ip), _make_default_pkt(self.MAC_DEST, '45.10.0.3', sub2.ip), ] # Initialize subscriber list in subscriber controller. subscriber_ip_table = SubscriberIPTable() subscriber_ip_table.entries.extend([ SubscriberIPTableEntry(sid=SubscriberID(id='IMSI001010000000013')), SubscriberIPTableEntry(sid=SubscriberID(id='IMSI001010000000014')), ]) fut = Future() fut.set_result(subscriber_ip_table) self.subscriber_controller._poll_subscriber_list_done(fut) # Verify that after the poll, subscriber 2 flows are deleted while # subscriber 1 flows remain. sub1_query = RyuDirectFlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch(imsi=encode_imsi('IMSI001010000000013'))) sub2_query = RyuDirectFlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch(imsi=encode_imsi('IMSI001010000000014'))) flow_verifier = FlowVerifier([ FlowTest(sub1_query, 0, 2), FlowTest(sub2_query, 0, 0), ], lambda: None) # Send packets through pipeline and wait. with isolator1, isolator2, flow_verifier: # Send packets to create the metering flows. Note that these # packets will not be matched because the test setup does not # support outputting to port. for pkt in packets: pkt_sender.send(pkt) wait_after_send(self.testing_controller) # Update the subscriber list to delete subscriber 2. subscriber_ip_table = SubscriberIPTable() subscriber_ip_table.entries.extend([ SubscriberIPTableEntry(sid=SubscriberID( id='IMSI001010000000013')), ]) fut = Future() fut.set_result(subscriber_ip_table) self.subscriber_controller._poll_subscriber_list_done(fut) flow_verifier.verify()
def test_input_output(self): """ """ sub1 = SubContextConfig('IMSI001010000088888', '192.168.128.74', 4) quota = 1024 # bytes # return only rx (downlink) packets self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[ session_manager_pb2.CreditUpdateResponse( success=True, sid=sub1.imsi, charging_key=1, credit=session_manager_pb2.ChargingCredit( granted_units=session_manager_pb2.GrantedUnits( rx=session_manager_pb2.CreditUnit( is_valid=True, volume=quota, ), ), ), ) ], static_rules=[ session_manager_pb2.StaticRuleInstall( rule_id="simple_match") ], ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) update_complete = hub.Queue() self.test_util.controller.mock_update_session = Mock( side_effect=get_standard_update_response(update_complete, None, quota, is_final=False), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.assertEqual( self.test_util.controller.mock_create_session.call_count, 1) packets = get_packets_for_flows( sub1, self.test_util.static_rules["simple_match"].flow_list) packet_count = int(quota / len(packets[0])) + 1 self.test_util.thread.run_in_greenthread( self.test_util.get_packet_sender([sub1], packets, packet_count), ) self.assertIsNone(get_from_queue(update_complete)) self.assertEqual( self.test_util.controller.mock_update_session.call_count, 0) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual( self.test_util.controller.mock_terminate_session.call_count, 1) # now attach with tx (uplink packets) self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[ session_manager_pb2.CreditUpdateResponse( success=True, sid=sub1.imsi, charging_key=1, credit=session_manager_pb2.ChargingCredit( granted_units=session_manager_pb2.GrantedUnits( tx=session_manager_pb2.CreditUnit( is_valid=True, volume=quota, ), ), ), ) ], static_rules=[ session_manager_pb2.StaticRuleInstall( rule_id="simple_match") ], ), ) self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub1.imsi), ue_ipv4=sub1.ip, ), ) self.test_util.thread.run_in_greenthread( self.test_util.get_packet_sender([sub1], packets, packet_count), ) self.assertIsNotNone(get_from_queue(update_complete)) self.assertEqual( self.test_util.controller.mock_update_session.call_count, 1) self.test_util.sessiond.EndSession(SubscriberID(id=sub1.imsi)) self.assertEqual( self.test_util.controller.mock_terminate_session.call_count, 2)
def test_multiple_subscribers(self): """ Test credit tracking with multiple rules and 32 subscribers, each using up their quota and reporting to the OCS """ subs = [ SubContextConfig( 'IMSI0010100000888{}'.format(i), '192.168.128.{}'.format(i), 4, ) for i in range(32) ] quota = 1024 # bytes # create some rules rule1 = create_uplink_rule("rule1", 2, '46.10.0.1') rule2 = create_uplink_rule("rule2", 0, '47.10.0.1', tracking=PolicyRule.NO_TRACKING) rule3 = create_uplink_rule("rule3", 3, '49.10.0.1') self.test_util.static_rules["rule1"] = rule1 self.test_util.static_rules["rule2"] = rule2 hub.sleep(2) # wait for policies # set up mocks self.test_util.controller.mock_create_session = Mock( return_value=session_manager_pb2.CreateSessionResponse( credits=[ create_update_response("", 2, quota), create_update_response("", 3, quota), ], static_rules=[ session_manager_pb2.StaticRuleInstall(rule_id="rule1"), session_manager_pb2.StaticRuleInstall(rule_id="rule2"), ], dynamic_rules=[ session_manager_pb2.DynamicRuleInstall(policy_rule=rule3) ], ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=session_manager_pb2.SessionTerminateResponse(), ) update_complete = hub.Queue() self.test_util.controller.mock_update_session = Mock( side_effect=get_standard_update_response(update_complete, None, quota, is_final=True), ) # initiate sessions for sub in subs: self.test_util.sessiond.CreateSession( session_manager_pb2.LocalCreateSessionRequest( sid=SubscriberID(id=sub.imsi), ue_ipv4=sub.ip, ), ) self.assertEqual( self.test_util.controller.mock_create_session.call_count, len(subs)) # send packets towards all 3 rules flows = [rule.flow_list[0] for rule in [rule1, rule2, rule3]] packets = [] for sub in subs: packets.extend(get_packets_for_flows(sub, flows)) packet_count = int(quota / len(packets[0])) + 1 self.test_util.thread.run_in_greenthread( self.test_util.get_packet_sender(subs, packets, packet_count), ) # wait for responses for keys 2 and 3 (key 1 is not tracked) expected_keys = {(sub.imsi, key) for sub in subs for key in [2, 3]} for _ in range(len(expected_keys)): update = get_from_queue(update_complete) self.assertIsNotNone(update) imsiKey = (update.sid, update.usage.charging_key) self.assertTrue(imsiKey in expected_keys) expected_keys.remove(imsiKey) for sub in subs: self.test_util.sessiond.EndSession(SubscriberID(id=sub.imsi)) self.assertEqual( self.test_util.controller.mock_terminate_session.call_count, len(subs))
def test_reauth(self): """ Send a Gx reauth request which installs one new static rule, one new dynamic rule, and removes one static and one dynamic rule. """ dynamic_rule1 = create_uplink_rule('dynamic1', 1, '46.10.10.1', tracking=PolicyRule.NO_TRACKING) dynamic_rule2 = create_uplink_rule('dynamic2', 1, '46.10.10.2', tracking=PolicyRule.NO_TRACKING) # Initialize sub with 1 static and 1 dynamic rule sub = SubContextConfig('IMSI001010000088888', '192.168.128.74', default_ambr_config, 4) self.test_util.controller.mock_create_session = Mock( return_value=CreateSessionResponse( credits=[create_update_response(sub.imsi, 1, 1024)], static_rules=[ session_manager_pb2.StaticRuleInstall(rule_id='policy1') ], dynamic_rules=[ session_manager_pb2.DynamicRuleInstall( policy_rule=dynamic_rule1) ], usage_monitors=[], ), ) self.test_util.controller.mock_terminate_session = Mock( return_value=SessionTerminateResponse(), ) self.test_util.sessiond.CreateSession( LocalCreateSessionRequest( sid=SubscriberID(id=sub.imsi), ue_ipv4=sub.ip, )) self.assertEqual( self.test_util.controller.mock_create_session.call_count, 1, ) # first, send some packets so we know that the uplink rules are # accepting traffic self._assert_rules( sub, [ session_manager_pb2.DynamicRuleInstall( policy_rule=self.test_util.static_rules['policy1']), session_manager_pb2.DynamicRuleInstall( policy_rule=dynamic_rule1) ], ) # Now via reauth, remove the old rules and install new uplink rules # Verify the new uplink rules allow traffic reauth_result = self.test_util.proxy_responder.PolicyReAuth( PolicyReAuthRequest( imsi=sub.imsi, rules_to_remove=['dynamic1', 'policy1'], rules_to_install=[ session_manager_pb2.StaticRuleInstall(rule_id='policy2') ], dynamic_rules_to_install=[ session_manager_pb2.DynamicRuleInstall( policy_rule=dynamic_rule2) ], )) self.assertEqual( reauth_result.result, session_manager_pb2.UPDATE_INITIATED, ) self.assertEqual(len(reauth_result.failed_rules), 0) self._assert_rules( sub, [ session_manager_pb2.DynamicRuleInstall( policy_rule=self.test_util.static_rules['policy2']), session_manager_pb2.DynamicRuleInstall( policy_rule=dynamic_rule2) ], ) # Verify the old rules no longer allow traffic (uninstalled) self._assert_rules( sub, [ session_manager_pb2.DynamicRuleInstall( policy_rule=self.test_util.static_rules['policy1']), session_manager_pb2.DynamicRuleInstall( policy_rule=dynamic_rule1) ], expected=0, )