def test_url_redirect(self): """ Partial redirection test, checks if flows were added properly for url based redirection. Assert: 1 Packet is matched Packet bypass flows are added Flow learn action is triggered - another flow is added to the table """ fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller) redirect_ips = ["185.128.101.5", "185.128.121.4"] self.enforcement_controller._redirect_manager._dns_cache.get( "about.sha.ddih.org", lambda: redirect_ips, max_age=42) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list = [FlowDescription(match=FlowMatch())] policy = PolicyRule(id='redir_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=2, server_address="http://about.sha.ddih.org/")) # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext(imsi, sub_ip, self.enforcement_controller, self._tbl_num) setup_flows_request = SetupFlowsRequest(requests=[ ActivateFlowsRequest( sid=SIDUtils.to_pb(imsi), ip_addr=sub_ip, policies=[VersionedPolicy(rule=policy, version=1)]), ], epoch=global_epoch) fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller, setup_flows_request=setup_flows_request) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packet = TCPPacketBuilder()\ .set_tcp_layer(42132, 80, 321)\ .set_tcp_flags("S")\ .set_ip_layer('151.42.41.122', sub_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with isolator, sub_context, snapshot_verifier: pkt_sender.send(packet)
def test_enforcement_restart(self): """ Adds rules using the setup feature 1) Empty SetupFlowsRequest - assert default flows 2) Add 2 imsis, add 2 policies(sub1_rule_temp, sub2_rule_keep), - assert everything is properly added 3) Same imsis 1 new policy, 1 old (sub2_new_rule, sub2_rule_keep) - assert everything is properly added 4) Empty SetupFlowsRequest - assert default flows """ self.enforcement_controller._rule_mapper = RuleIDToNumMapper() self.enforcement_stats_controller._rule_mapper = RuleIDToNumMapper() fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'default_flows') with snapshot_verifier: pass imsi1 = 'IMSI010000000088888' imsi2 = 'IMSI010000000012345' sub2_ip = '192.168.128.74' flow_list1 = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT), FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.11.0.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] flow_list2 = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('10.10.1.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies1 = [ VersionedPolicy( rule=PolicyRule(id='sub1_rule_temp', priority=2, flow_list=flow_list1), version=1, ) ] policies2 = [ VersionedPolicy( rule=PolicyRule(id='sub2_rule_keep', priority=3, flow_list=flow_list2), version=1, ) ] enf_stat_name = [ imsi1 + '|sub1_rule_temp' + '|' + sub2_ip, imsi2 + '|sub2_rule_keep' + '|' + sub2_ip ] self.service_manager.session_rule_version_mapper.save_version( imsi1, convert_ipv4_str_to_ip_proto(sub2_ip), 'sub1_rule_temp', 1) self.service_manager.session_rule_version_mapper.save_version( imsi2, convert_ipv4_str_to_ip_proto(sub2_ip), 'sub2_rule_keep', 1) setup_flows_request = SetupFlowsRequest(requests=[ ActivateFlowsRequest(sid=SIDUtils.to_pb(imsi1), ip_addr=sub2_ip, policies=policies1), ActivateFlowsRequest(sid=SIDUtils.to_pb(imsi2), ip_addr=sub2_ip, policies=policies2), ], epoch=global_epoch) # Simulate clearing the dict self.service_manager.session_rule_version_mapper\ ._version_by_imsi_and_rule = {} fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller, setup_flows_request=setup_flows_request) sub_context = RyuDirectSubscriberContext(imsi2, sub2_ip, self.enforcement_controller, self._enforcement_tbl_num) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packets = IPPacketBuilder()\ .set_ip_layer('10.10.1.8/20', sub2_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'before_restart') with isolator, snapshot_verifier: pkt_sender.send(packets) flow_list1 = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('24.10.0.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies = [ VersionedPolicy( rule=PolicyRule(id='sub2_new_rule', priority=2, flow_list=flow_list1), version=1, ), VersionedPolicy( rule=PolicyRule(id='sub2_rule_keep', priority=3, flow_list=flow_list2), version=1, ), ] enf_stat_name = [ imsi2 + '|sub2_new_rule' + '|' + sub2_ip, imsi2 + '|sub2_rule_keep' + '|' + sub2_ip ] setup_flows_request = SetupFlowsRequest(requests=[ ActivateFlowsRequest( sid=SIDUtils.to_pb(imsi2), ip_addr=sub2_ip, policies=policies, ) ], epoch=global_epoch) fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller, setup_flows_request=setup_flows_request) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'after_restart') with snapshot_verifier: pass fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'default_flows_w_packets') with snapshot_verifier: pass
def test_enforcement_stats_restart(self): """ Adds 2 policies to subscriber, verifies that EnforcementStatsController reports correct stats to sessiond Assert: UPLINK policy matches 128 packets (*34 = 4352 bytes) DOWNLINK policy matches 256 packets (*34 = 8704 bytes) No other stats are reported The controller is then restarted with the same SetupFlowsRequest, - assert flows keep their packet counts """ self.enforcement_stats_controller._report_usage.reset_mock() fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'default_flows') with snapshot_verifier: pass imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' num_pkts_tx_match = 128 num_pkts_rx_match = 256 """ Create 2 policy rules for the subscriber """ flow_list1 = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/25'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] flow_list2 = [ FlowDescription(match=FlowMatch( ip_src=convert_ipv4_str_to_ip_proto('45.10.0.0/24'), direction=FlowMatch.DOWNLINK), action=FlowDescription.PERMIT) ] policies = [ VersionedPolicy( rule=PolicyRule(id='tx_match', priority=3, flow_list=flow_list1), version=1, ), VersionedPolicy( rule=PolicyRule(id='rx_match', priority=5, flow_list=flow_list2), version=1, ), ] enf_stat_name = [ imsi + '|tx_match' + '|' + sub_ip, imsi + '|rx_match' + '|' + sub_ip ] self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'tx_match', 1) self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rx_match', 1) """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._enforcement_tbl_num, self.enforcement_stats_controller, nuke_flows_on_exit=False).add_policy(policies[0]).add_policy( policies[1]) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) """ Create 2 sets of packets, for policry rule1&2 """ pkt_sender = ScapyPacketInjector(self.IFACE) packet1 = IPPacketBuilder()\ .set_ip_layer('45.10.0.0/20', sub_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() packet2 = IPPacketBuilder()\ .set_ip_layer(sub_ip, '45.10.0.0/20')\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() # =========================== Verification =========================== snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'initial_flows') """ Send packets, wait until pkts are received by ovs and enf stats """ with isolator, sub_context, snapshot_verifier: pkt_sender.send(packet1) pkt_sender.send(packet2) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[enf_stat_name[0]].sid, imsi) self.assertEqual(stats[enf_stat_name[0]].rule_id, "tx_match") self.assertEqual(stats[enf_stat_name[0]].bytes_rx, 0) self.assertEqual(stats[enf_stat_name[0]].bytes_tx, num_pkts_tx_match * len(packet1)) self.assertEqual(stats[enf_stat_name[1]].sid, imsi) self.assertEqual(stats[enf_stat_name[1]].rule_id, "rx_match") self.assertEqual(stats[enf_stat_name[1]].bytes_tx, 0) self.assertEqual(stats[enf_stat_name[1]].bytes_rx, 5120) # downlink packets will discount ethernet header by default # so, only count the IP portion total_bytes_pkt2 = num_pkts_rx_match * len(packet2[IP]) self.assertEqual(stats[enf_stat_name[1]].bytes_rx, total_bytes_pkt2) # NOTE this value is 8 because the EnforcementStatsController rule # reporting doesn't reset on clearing flows(lingers from old tests) self.assertEqual(len(stats), 3) setup_flows_request = SetupFlowsRequest(requests=[ ActivateFlowsRequest(sid=SIDUtils.to_pb(imsi), ip_addr=sub_ip, policies=[policies[0], policies[1]]), ], epoch=global_epoch) fake_controller_setup( enf_controller=self.enforcement_controller, enf_stats_controller=self.enforcement_stats_controller, startup_flow_controller=self.startup_flows_contoller, setup_flows_request=setup_flows_request) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'after_restart') with snapshot_verifier: pass
def test_deny_rule_install(self): """ Adds a policy to a subscriber. Verifies that flows are properly installed in enforcement and enforcement stats. Assert: Policy classification flows installed in enforcement Policy match flows installed in enforcement_stats """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) imsi = 'IMSI001010000000014' sub_ip = '192.16.15.7' num_pkt_unmatched = 4096 flow_list = [FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('1.1.0.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.DENY) ] policy = VersionedPolicy( rule=PolicyRule(id='rule1', priority=3, flow_list=flow_list), version=1, ) self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1', 1) """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller ).add_policy(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub_context.cfg) .build_requests(), self.testing_controller ) pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder() \ .set_ip_layer('45.10.0.0/20', sub_ip) \ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \ .build() # =========================== Verification =========================== # Verifies that 1 flow is installed in enforcement and 2 flows are # installed in enforcement stats, one for uplink and one for downlink. snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with isolator, sub_context, snapshot_verifier: pkt_sender.send(packet) enf_stat_name = imsi + '|' + self.DEFAULT_DROP_FLOW_NAME + '|' + sub_ip wait_for_enforcement_stats(self.enforcement_stats_controller, [enf_stat_name]) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[enf_stat_name].sid, imsi) self.assertEqual(stats[enf_stat_name].rule_id, self.DEFAULT_DROP_FLOW_NAME) self.assertEqual(stats[enf_stat_name].dropped_rx, 0) self.assertEqual(stats[enf_stat_name].dropped_tx, num_pkt_unmatched * len(packet))
def test_rule_deactivation(self): """ Adds a policy to a subscriber, and then deletes it by incrementing the version, verifies that the usage stats is correctly reported and the flows are deleted. Assert: UPLINK policy matches 128 packets (*34 = 4352 bytes) Flows are deleted No other stats are reported """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' num_pkts_tx_match = 128 flow_list = [FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/25'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policy = VersionedPolicy( rule=PolicyRule(id='rule1', priority=3, flow_list=flow_list), version=1, ) enf_stat_name = imsi + '|rule1' + '|' + sub_ip self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1', 1) """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller ).add_policy(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub_context.cfg) .build_requests(), self.testing_controller ) """ Create a packet """ pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder() \ .set_ip_layer('45.10.0.0/20', sub_ip) \ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \ .build() # =========================== Verification =========================== """ Verify that flows are properly deleted """ snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) """ Send packets, wait until packet is received by ovs and enf stats and then deactivate the rule in enforcement controller. This emulates the case where there is unreported traffic after rule deactivation. """ with isolator, sub_context, snapshot_verifier: self.enforcement_stats_controller._report_usage.reset_mock() pkt_sender.send(packet) self.service_manager.session_rule_version_mapper. \ save_version(imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1', 2) self.enforcement_controller.deactivate_rules( imsi, convert_ipv4_str_to_ip_proto(sub_ip), [policy.rule.id]) wait_for_enforcement_stats(self.enforcement_stats_controller, [enf_stat_name]) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[enf_stat_name].sid, imsi) self.assertEqual(stats[enf_stat_name].rule_id, "rule1") self.assertEqual(stats[enf_stat_name].rule_version, 1) self.assertEqual(stats[enf_stat_name].bytes_rx, 0) self.assertEqual(stats[enf_stat_name].bytes_tx, num_pkts_tx_match * len(packet)) self.assertEqual(len(stats), 2) self.enforcement_stats_controller.deactivate_default_flow( imsi, convert_ipv4_str_to_ip_proto(sub_ip)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'nuke_ue') with snapshot_verifier: pass
def test_ipv4_redirect(self): """ Partial redirection test, checks if flows were added properly for ipv4 based redirection. Assert: 1 Packet is matched Packet bypass flows are added Flow learn action is triggered - another flow is added to the table """ fake_controller_setup(self.enforcement_controller) redirect_ip = "54.12.31.42" imsi = 'IMSI012000000088888' sub_ip = '192.168.128.74' flow_list = [FlowDescription(match=FlowMatch())] policy = PolicyRule(id='redir_ip_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=0, server_address=redirect_ip)) # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._tbl_num).add_dynamic_rule(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packet = TCPPacketBuilder()\ .set_tcp_layer(42132, 80, 321)\ .set_tcp_flags("S")\ .set_ip_layer('151.42.41.122', sub_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() # Check if these flows were added (queries should return flows) permit_outbound = FlowQuery(self._tbl_num, self.testing_controller, match=flow_match_to_magma_match( FlowMatch(ipv4_dst=redirect_ip, direction=FlowMatch.UPLINK))) permit_inbound = FlowQuery(self._tbl_num, self.testing_controller, match=flow_match_to_magma_match( FlowMatch( ipv4_src=redirect_ip, direction=FlowMatch.DOWNLINK))) learn_action_flow = flow_match_to_magma_match( FlowMatch(ip_proto=6, direction=FlowMatch.DOWNLINK, ipv4_src=self.BRIDGE_IP_ADDRESS, ipv4_dst=sub_ip)) learn_action_query = FlowQuery(self._tbl_num, self.testing_controller, learn_action_flow) # =========================== Verification =========================== # 1 packet sent, permit rules installed, learn action installed. Since # the enforcement table is entered via the DPI table and the scratch # enforcement table, the number of packets handled by the table is 2. flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), 2), FlowTest(permit_outbound, 0, flow_count=1), FlowTest(permit_inbound, 0, flow_count=1), FlowTest(learn_action_query, 0, flow_count=1) ], lambda: wait_after_send(self.testing_controller)) with isolator, sub_context, flow_verifier: pkt_sender.send(packet) assert_bridge_snapshot_match(self, self.BRIDGE, self.service_manager) flow_verifier.verify()
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_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 blocklist. Assert: Both packets are not 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. The directions of the packets are opposite of the # installed match flow, so there should not matches. pkt_sender = ScapyPacketInjector(self.BRIDGE) packets = [ _build_default_ip_packet(self.MAC_DEST, self.OUTBOUND_TEST_IP, sub.ip), _build_default_ip_packet(self.MAC_DEST, 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_enforcement_restart(self): """ Adds rules using the setup feature 1) Empty SetupFlowsRequest - assert default flows 2) Add 2 imsis, add 2 policies(sub1_rule_temp, sub2_rule_keep), - assert everything is properly added 3) Same imsis 1 new policy, 1 old (sub2_new_rule, sub2_rule_keep) - assert everything is properly added 4) Empty SetupFlowsRequest - assert default flows """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller, self.startup_flows_contoller) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'default_flows') with snapshot_verifier: pass imsi1 = 'IMSI010000000088888' imsi2 = 'IMSI010000000012345' sub2_ip = '192.168.128.74' flow_list1 = [ FlowDescription(match=FlowMatch(ipv4_dst='45.10.0.0/24', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT), FlowDescription(match=FlowMatch(ipv4_dst='45.11.0.0/24', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] flow_list2 = [ FlowDescription(match=FlowMatch(ipv4_dst='10.10.1.0/24', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies1 = [ PolicyRule(id='sub1_rule_temp', priority=2, flow_list=flow_list1), ] policies2 = [ PolicyRule(id='sub2_rule_keep', priority=3, flow_list=flow_list2) ] enf_stat_name = [imsi1 + '|sub1_rule_temp', imsi2 + '|sub2_rule_keep'] self.service_manager.session_rule_version_mapper.update_version( imsi1, 'sub1_rule_temp') self.service_manager.session_rule_version_mapper.update_version( imsi2, 'sub2_rule_keep') setup_flows_request = SetupFlowsRequest(requests=[ ActivateFlowsRequest(sid=SIDUtils.to_pb(imsi1), dynamic_rules=policies1), ActivateFlowsRequest(sid=SIDUtils.to_pb(imsi2), dynamic_rules=policies2), ], epoch=global_epoch) fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller, self.startup_flows_contoller, setup_flows_request) sub_context = RyuDirectSubscriberContext(imsi2, sub2_ip, self.enforcement_controller, self._enforcement_tbl_num) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packets = IPPacketBuilder()\ .set_ip_layer('10.10.1.8/20', sub2_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() pkts_sent = 4096 pkts_matched = 256 flow_query = FlowQuery(self._enforcement_tbl_num, self.testing_controller, match=flow_match_to_magma_match( flow_list2[0].match)) flow_verifier = FlowVerifier([ FlowTest( FlowQuery(self._enforcement_tbl_num, self.testing_controller), pkts_sent), FlowTest(flow_query, pkts_matched) ], self._wait_func(enf_stat_name)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'before_restart') with isolator, flow_verifier, snapshot_verifier: pkt_sender.send(packets) flow_verifier.verify() flow_list1 = [ FlowDescription(match=FlowMatch(ipv4_dst='24.10.0.0/24', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies = [ PolicyRule(id='sub2_new_rule', priority=2, flow_list=flow_list1), PolicyRule(id='sub2_rule_keep', priority=3, flow_list=flow_list2) ] self.service_manager.session_rule_version_mapper.update_version( imsi2, 'sub2_new_rule') enf_stat_name = [imsi2 + '|sub2_new_rule', imsi2 + '|sub2_rule_keep'] setup_flows_request = SetupFlowsRequest(requests=[ ActivateFlowsRequest(sid=SIDUtils.to_pb(imsi2), dynamic_rules=policies) ], epoch=global_epoch) fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller, self.startup_flows_contoller, setup_flows_request) flow_verifier = FlowVerifier([FlowTest(flow_query, pkts_matched)], self._wait_func(enf_stat_name)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'after_restart') with flow_verifier, snapshot_verifier: pass fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller, self.startup_flows_contoller) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, 'default_flows') with snapshot_verifier: pass
def test_subscriber_policy(self): """ Add policy to subscriber, send 4096 packets Assert: Packets are properly matched with the 'simple_match' policy Send /20 (4096) packets, match /16 (256) packets """ fake_controller_setup(self.enforcement_controller) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list1 = [ FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/24'), direction=FlowMatch.UPLINK, ), action=FlowDescription.PERMIT, ), ] policies = [ VersionedPolicy( rule=PolicyRule(id='simple_match', priority=2, flow_list=flow_list1), version=1, ), ] pkts_matched = 256 pkts_sent = 4096 # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._tbl_num, ).add_policy(policies[0]) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller, ) pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder()\ .set_ip_layer('45.10.0.0/20', sub_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() flow_query = FlowQuery( self._tbl_num, self.testing_controller, match=flow_match_to_magma_match(flow_list1[0].match), ) # =========================== Verification =========================== # Verify aggregate table stats, subscriber 1 'simple_match' pkt count flow_verifier = FlowVerifier( [ FlowTest( FlowQuery(self._tbl_num, self.testing_controller), pkts_sent, ), FlowTest(flow_query, pkts_matched), ], lambda: wait_after_send(self.testing_controller), ) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with isolator, sub_context, flow_verifier, snapshot_verifier: pkt_sender.send(packet) flow_verifier.verify()
def test_two_subscribers(self): """ Add 2 subscribers at the same time Assert: For subcriber1 the packets are matched to the proper policy For subcriber2 the packets are matched to the proper policy The total packet delta in the table is from the above matches """ fake_controller_setup(self.enforcement_controller) pkt_sender = ScapyPacketInjector(self.IFACE) ip_match = [FlowDescription( match=FlowMatch(ip_src=convert_ipv4_str_to_ip_proto('8.8.8.0/24'), direction=1), action=1) ] tcp_match = [FlowDescription( match=FlowMatch(ip_proto=6, direction=FlowMatch.DOWNLINK), action=FlowDescription.DENY) ] self._static_rule_dict['t'] = PolicyRule(id='t', priority=2, flow_list=ip_match) # =========================== Subscriber 1 =========================== sub_context1 = RyuDirectSubscriberContext( 'IMSI208950001111111', '192.168.128.5', self.enforcement_controller, self._tbl_num ).add_static_rule('t') isolator1 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub_context1.cfg) .build_requests(), self.testing_controller ) packet_ip = IPPacketBuilder()\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .set_ip_layer(sub_context1.cfg.ip, '8.8.8.8')\ .build() s1_pkts_sent = 29 pkts_to_send = [PktsToSend(packet_ip, s1_pkts_sent)] flow_query1 = FlowQuery( self._tbl_num, self.testing_controller, match=flow_match_to_magma_match(ip_match[0].match) ) s1 = SubTest( sub_context1, isolator1, FlowTest(flow_query1, s1_pkts_sent) ) # =========================== Subscriber 2 =========================== sub_context2 = RyuDirectSubscriberContext( 'IMSI911500451242001', '192.168.128.100', self.enforcement_controller, self._tbl_num ).add_dynamic_rule( PolicyRule(id='qqq', priority=2, flow_list=tcp_match) ) isolator2 = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub_context2.cfg) .build_requests(), self.testing_controller ) packet_tcp = TCPPacketBuilder()\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .set_ip_layer(sub_context2.cfg.ip, '15.0.0.8')\ .build() s2_pkts_sent = 18 pkts_to_send.append(PktsToSend(packet_tcp, s2_pkts_sent)) flow_query2 = FlowQuery( self._tbl_num, self.testing_controller, match=flow_match_to_magma_match(tcp_match[0].match) ) s2 = SubTest( sub_context2, isolator2, FlowTest(flow_query2, s2_pkts_sent) ) # =========================== Verification =========================== # Verify aggregate table stats, subscriber 1 & 2 flows packet matches pkts = s1_pkts_sent + s2_pkts_sent flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), pkts), s1.flowtest_list, s2.flowtest_list ], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with s1.isolator, s1.context, s2.isolator, s2.context, flow_verifier, \ snapshot_verifier: for pkt in pkts_to_send: pkt_sender.send(pkt.pkt, pkt.num) flow_verifier.verify()
def test_rule_deactivation(self): """ Adds a policy to a subscriber, and then deletes it by incrementing the version, verifies that the usage stats is correctly reported and the flows are deleted. Assert: UPLINK policy matches 128 packets (*34 = 4352 bytes) Flows are deleted No other stats are reported """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' num_pkts_tx_match = 128 flow_list = [ FlowDescription(match=FlowMatch(ipv4_dst='45.10.0.0/25', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policy = PolicyRule(id='rule1', priority=3, flow_list=flow_list) enf_stat_name = imsi + '|rule1' self.service_manager.session_rule_version_mapper.update_version( imsi, 'rule1') version = \ self.service_manager.session_rule_version_mapper.get_version( imsi, 'rule1') """ Setup subscriber, setup table_isolation to fwd pkts """ self._static_rule_dict[policy.id] = policy sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller).add_static_rule(policy.id) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) """ Create a packet """ pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder() \ .set_ip_layer('45.10.0.0/20', sub_ip) \ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \ .build() # =========================== Verification =========================== rule_num = self.enforcement_stats_controller._rule_mapper \ .get_or_create_rule_num(policy.id) enf_query = FlowQuery(self._main_tbl_num, self.testing_controller, match=flow_match_to_magma_match( FlowMatch(ipv4_dst='45.10.0.0/25', direction=FlowMatch.UPLINK)), cookie=rule_num) es_query = FlowQuery(self._scratch_tbl_num, self.testing_controller, match=MagmaMatch(imsi=encode_imsi(imsi), reg2=rule_num, rule_version=version), cookie=rule_num) """ Verify that flows are properly deleted """ verify_enforcement_stats = FlowVerifier([ FlowTest(es_query, 0, flow_count=0), ], self._wait_func([enf_stat_name])) verify_enforcement = FlowVerifier([ FlowTest(enf_query, 0, flow_count=0), ], lambda: None) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) """ Send packets, wait until packet is received by ovs and enf stats and then deactivate the rule in enforcement controller. This emulates the case where there is unreported traffic after rule deactivation. """ with isolator, sub_context, verify_enforcement, snapshot_verifier: with verify_enforcement_stats: self.enforcement_stats_controller._report_usage.reset_mock() pkt_sender.send(packet) self.service_manager.session_rule_version_mapper. \ update_version(imsi, 'rule1') self.enforcement_controller.deactivate_rules(imsi, [policy.id]) verify_enforcement.verify() verify_enforcement_stats.verify() stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[enf_stat_name].sid, imsi) self.assertEqual(stats[enf_stat_name].rule_id, "rule1") self.assertEqual(stats[enf_stat_name].bytes_rx, 0) self.assertEqual(stats[enf_stat_name].bytes_tx, num_pkts_tx_match * len(packet)) self.assertEqual(len(stats), 1)
def test_outbound_ip_match(self): """ Outbound ip match test, checks that packets are properly matched when the outbound traffic matches an ip in the blocklist. Assert: Both packets are matched Ip match flows are added """ sub = self._setup_subscribers() 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, sub.ip, self.OUTBOUND_TEST_IP), _build_default_ip_packet(self.MAC_DEST, sub.ip, self.BOTH_DIR_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.IN, ipv4_src=self.OUTBOUND_TEST_IP, ), ), FlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch( eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN, ipv4_src=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 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_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_subscriber_policy(self): """ Adds 2 policies to subscriber, verifies that EnforcementStatsController reports correct stats to sessiond Assert: UPLINK policy matches 128 packets (*34 = 4352 bytes) DOWNLINK policy matches 256 packets (*34 = 8704 bytes) No other stats are reported """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' num_pkts_tx_match = 128 num_pkts_rx_match = 256 """ Create 2 policy rules for the subscriber """ flow_list1 = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/25'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] flow_list2 = [ FlowDescription(match=FlowMatch( ip_src=convert_ipv4_str_to_ip_proto('45.10.0.0/24'), direction=FlowMatch.DOWNLINK), action=FlowDescription.PERMIT) ] policies = [ PolicyRule(id='tx_match', priority=3, flow_list=flow_list1), PolicyRule(id='rx_match', priority=5, flow_list=flow_list2) ] enf_stat_name = [ imsi + '|tx_match' + '|' + sub_ip, imsi + '|rx_match' + '|' + sub_ip ] self.service_manager.session_rule_version_mapper.update_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'tx_match') self.service_manager.session_rule_version_mapper.update_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rx_match') """ Setup subscriber, setup table_isolation to fwd pkts """ self._static_rule_dict[policies[0].id] = policies[0] self._static_rule_dict[policies[1].id] = policies[1] sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller).add_static_rule( policies[0].id).add_static_rule(policies[1].id) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) """ Create 2 sets of packets, for policry rule1&2 """ pkt_sender = ScapyPacketInjector(self.IFACE) packet1 = IPPacketBuilder()\ .set_ip_layer('45.10.0.0/20', sub_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() packet2 = IPPacketBuilder()\ .set_ip_layer(sub_ip, '45.10.0.0/20')\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() # =========================== Verification =========================== snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) """ Send packets, wait until pkts are received by ovs and enf stats """ with isolator, sub_context, snapshot_verifier: pkt_sender.send(packet1) pkt_sender.send(packet2) wait_for_enforcement_stats(self.enforcement_stats_controller, enf_stat_name) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[enf_stat_name[0]].sid, imsi) self.assertEqual(stats[enf_stat_name[0]].rule_id, "tx_match") self.assertEqual(stats[enf_stat_name[0]].bytes_rx, 0) self.assertEqual(stats[enf_stat_name[0]].bytes_tx, num_pkts_tx_match * len(packet1)) self.assertEqual(stats[enf_stat_name[1]].sid, imsi) self.assertEqual(stats[enf_stat_name[1]].rule_id, "rx_match") self.assertEqual(stats[enf_stat_name[1]].bytes_tx, 0) # downlink packets will discount ethernet header by default # so, only count the IP portion total_bytes_pkt2 = num_pkts_rx_match * len(packet2[IP]) self.assertEqual(stats[enf_stat_name[1]].bytes_rx, total_bytes_pkt2) self.assertEqual(len(stats), 2)
def test_url_redirect(self): """ Partial redirection test, checks if flows were added properly for url based redirection. Assert: 1 Packet is matched Packet bypass flows are added Flow learn action is triggered - another flow is added to the table """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller, self.startup_flows_contoller) redirect_ips = ["185.128.101.5", "185.128.121.4"] self.enforcement_controller._redirect_manager._dns_cache.get( "about.sha.ddih.org", lambda: redirect_ips, max_age=42) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list = [FlowDescription(match=FlowMatch())] policy = PolicyRule(id='redir_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=2, server_address="http://about.sha.ddih.org/")) # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext(imsi, sub_ip, self.enforcement_controller, self._tbl_num) setup_flows_request = SetupFlowsRequest(requests=[ ActivateFlowsRequest(sid=SIDUtils.to_pb(imsi), ip_addr=sub_ip, dynamic_rules=[policy]), ], epoch=global_epoch) fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller, self.startup_flows_contoller, setup_flows_request) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packet = TCPPacketBuilder()\ .set_tcp_layer(42132, 80, 321)\ .set_tcp_flags("S")\ .set_ip_layer('151.42.41.122', sub_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() # Check if these flows were added (queries should return flows) permit_outbound, permit_inbound = [], [] for ip in redirect_ips: permit_outbound.append( FlowQuery(self._tbl_num, self.testing_controller, match=flow_match_to_magma_match( FlowMatch(ipv4_dst=ip, direction=FlowMatch.UPLINK)))) permit_inbound.append( FlowQuery(self._tbl_num, self.testing_controller, match=flow_match_to_magma_match( FlowMatch(ipv4_src=ip, direction=FlowMatch.DOWNLINK)))) learn_action_flow = flow_match_to_magma_match( FlowMatch(ip_proto=6, direction=FlowMatch.DOWNLINK, ipv4_src=self.BRIDGE_IP_ADDRESS, ipv4_dst=sub_ip)) learn_action_query = FlowQuery(self._tbl_num, self.testing_controller, learn_action_flow) # =========================== Verification =========================== # 1 packet sent, permit rules installed, learn action installed. Since # the enforcement table is entered via the DPI table and the scratch # enforcement table, the number of packets handled by the table is 2. flow_verifier = FlowVerifier( [ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), 2), FlowTest(learn_action_query, 0, flow_count=1) ] + [FlowTest(query, 0, flow_count=1) for query in permit_outbound] + [FlowTest(query, 0, flow_count=1) for query in permit_inbound], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with isolator, sub_context, flow_verifier, snapshot_verifier: pkt_sender.send(packet) flow_verifier.verify()
def test_rule_reactivation(self): """ Adds a policy to a subscriber, deletes it by incrementing the version, and add it back. Verifies that the usage stats is correctly reported, the old flows are deleted, and the new flows are installed. Assert: UPLINK policy matches 128 packets (*34 = 4352 bytes) Old flows are deleted New flows are installed No other stats are reported """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' num_pkts_tx_match = 128 flow_list = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/25'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policy = PolicyRule(id='rule1', priority=3, flow_list=flow_list) enf_stat_name = imsi + '|rule1' + '|' + sub_ip self.service_manager.session_rule_version_mapper.update_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1') """ Setup subscriber, setup table_isolation to fwd pkts """ self._static_rule_dict[policy.id] = policy sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller).add_static_rule(policy.id) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) """ Create a packet """ pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder() \ .set_ip_layer('45.10.0.0/20', sub_ip) \ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \ .build() # =========================== Verification =========================== """ Verify that flows are properly deleted """ snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) """ Send a packet, then deactivate and reactivate the same rule and send a packet. Wait until it is received by ovs and enf stats. """ with isolator, sub_context, snapshot_verifier: self.enforcement_stats_controller._report_usage.reset_mock() pkt_sender.send(packet) self.enforcement_stats_controller._report_usage.reset_mock() self.service_manager.session_rule_version_mapper. \ update_version(imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1') self.enforcement_controller.deactivate_rules( imsi, convert_ipv4_str_to_ip_proto(sub_ip), [policy.id]) self.enforcement_controller.activate_rules( imsi, convert_ipv4_str_to_ip_proto(sub_ip), None, [policy.id], []) self.enforcement_stats_controller.activate_rules( imsi, convert_ipv4_str_to_ip_proto(sub_ip), None, [policy.id], []) pkt_sender.send(packet) wait_for_enforcement_stats(self.enforcement_stats_controller, [enf_stat_name]) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) """ Verify both packets are reported after reactivation. """ self.assertEqual(stats[enf_stat_name].sid, imsi) self.assertEqual(stats[enf_stat_name].rule_id, "rule1") self.assertEqual(stats[enf_stat_name].bytes_rx, 0) # TODO Figure out why this one fails. #self.assertEqual(stats[enf_stat_name].bytes_tx, # num_pkts_tx_match * len(packet)) self.assertEqual(len(stats), 1)
def test_redirect_policy(self): """ Add a redirect policy, verifies that EnforcementStatsController reports correct stats to sessiond Assert: 1 Packet is matched and reported """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) redirect_ips = ["185.128.101.5", "185.128.121.4"] self.enforcement_controller._redirect_manager._dns_cache.get( "about.sha.ddih.org", lambda: redirect_ips, max_age=42 ) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list = [FlowDescription(match=FlowMatch())] policy = VersionedPolicy( rule=PolicyRule( id='redir_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=2, server_address="http://about.sha.ddih.org/" ) ), version=1, ) stat_name = imsi + '|redir_test' + '|' + sub_ip self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'redir_test', 1) """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller ).add_policy(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber(sub_context.cfg) .build_requests(), self.testing_controller ) pkt_sender = ScapyPacketInjector(self.IFACE) packet = TCPPacketBuilder() \ .set_tcp_layer(42132, 80, 321) \ .set_tcp_flags("S") \ .set_ip_layer('151.42.41.122', sub_ip) \ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \ .build() # =========================== Verification =========================== snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) """ Send packet, wait until pkts are received by ovs and enf stats """ with isolator, sub_context, snapshot_verifier: self.enforcement_stats_controller._report_usage.reset_mock() pkt_sender.send(packet) wait_for_enforcement_stats(self.enforcement_stats_controller, [stat_name]) """ Send packets, wait until pkts are received by ovs and enf stats """ stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[stat_name].sid, imsi) self.assertEqual(stats[stat_name].rule_id, "redir_test") self.assertEqual(stats[stat_name].bytes_rx, 0) self.assertEqual(stats[stat_name].bytes_tx, len(packet))
def test_subscriber_two_policies(self): """ Add 2 policies to subscriber Assert: Packets are properly matched with the 'match' policy The total packet delta in the table is from the above match """ fake_controller_setup(self.enforcement_controller) imsi = 'IMSI208950000000001' sub_ip = '192.168.128.74' flow_list1 = [ FlowDescription(match=FlowMatch( ip_src=convert_ipv4_str_to_ip_proto('15.0.0.0/24'), direction=FlowMatch.DOWNLINK), action=FlowDescription.DENY) ] flow_list2 = [ FlowDescription(match=FlowMatch(ip_proto=6, direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies = [ VersionedPolicy( rule=PolicyRule(id='match', priority=2, flow_list=flow_list1), version=1, ), VersionedPolicy( rule=PolicyRule(id='no_match', priority=2, flow_list=flow_list2), version=1, ), ] pkts_sent = 42 # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext(imsi, sub_ip, self.enforcement_controller, self._tbl_num) \ .add_policy(policies[0])\ .add_policy(policies[1]) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder()\ .set_ip_layer(sub_ip, '15.0.0.8')\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() flow_query = FlowQuery(self._tbl_num, self.testing_controller, match=flow_match_to_magma_match( flow_list1[0].match)) # =========================== Verification =========================== # Verify aggregate table stats, subscriber 1 'match' rule pkt count flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), pkts_sent), FlowTest(flow_query, pkts_sent) ], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with isolator, sub_context, flow_verifier, snapshot_verifier: pkt_sender.send(packet, pkts_sent) 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()