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 = PolicyRule(id='rule1', priority=3, flow_list=flow_list) 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 """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller).add_dynamic_rule(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_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 = PolicyRule(id='redir_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=2, server_address="http://about.sha.ddih.org/")) stat_name = imsi + '|redir_test' + '|' + sub_ip self.service_manager.session_rule_version_mapper.update_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'redir_test') """ 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_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() # =========================== 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_cookie_poll(self): """ Add a subscriber policy, verify flows are properly installed Assert: Query with RULE_NUM 1 returns proper values """ original = self.enforcement_stats_controller._poll_stats self.enforcement_stats_controller._poll_stats = MagicMock() self.enforcement_stats_controller.init_finished = False self.enforcement_controller.init_finished = True imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' 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 + '|' + "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) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) self.enforcement_stats_controller._report_usage.reset_mock() with sub_context, snapshot_verifier: self.enforcement_stats_controller.init_finished = True flows.send_stats_request( self.enforcement_stats_controller._datapath, self.enforcement_stats_controller.tbl_num, 0, flows.OVS_COOKIE_MATCH_ALL, ) 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].rule_id, 'rule1') self.enforcement_stats_controller._poll_stats = original self.assertEqual(len(stats), 2)
def func(): wait_after_send(self.testing_controller) wait_for_enforcement_stats(self.enforcement_stats_controller, stat_names)
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 = 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, ) """ 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: 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], ) policy.version = 2 self.enforcement_controller.activate_rules( imsi, None, None, convert_ipv4_str_to_ip_proto(sub_ip), None, [policy], 0, 0, ) self.enforcement_stats_controller.activate_rules( imsi, None, None, convert_ipv4_str_to_ip_proto(sub_ip), None, [policy], 0, 0, ) pkt_sender.send(packet) enf_stat_names = [ imsi + '|rule1' + '|' + sub_ip + '|' + "1", imsi + '|rule1' + '|' + sub_ip + '|' + "2", ] wait_for_enforcement_stats( self.enforcement_stats_controller, enf_stat_names, ) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list, ) for args in self.enforcement_stats_controller._report_usage.call_args_list: self.enforcement_stats_controller._delete_old_flows( args[0][0].values()) self.assertEqual(stats[enf_stat_names[0]].sid, imsi) self.assertEqual(stats[enf_stat_names[0]].rule_id, "rule1") self.assertEqual(stats[enf_stat_names[0]].rule_version, 1) self.assertEqual(stats[enf_stat_names[0]].bytes_rx, 0) self.assertEqual(len(stats), 3) self.enforcement_stats_controller._report_usage.reset_mock() wait_for_enforcement_stats( self.enforcement_stats_controller, [enf_stat_names[1]], ) 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_names[1]].sid, imsi) self.assertEqual(stats[enf_stat_names[1]].rule_id, "rule1") self.assertEqual(stats[enf_stat_names[1]].rule_version, 2) self.assertEqual(stats[enf_stat_names[1]].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), 2)
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 = [ 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 + '|' + "1", imsi + '|rx_match' + '|' + sub_ip + '|' + "1", ] 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._main_tbl_num, self.enforcement_stats_controller, ).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, ) """ 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), 3)
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 + '|' + "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) """ 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) for args in self.enforcement_stats_controller._report_usage.call_args_list: self.enforcement_stats_controller._delete_old_flows( args[0][0].values()) 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_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 + "|" + "1", imsi + '|rx_match' + '|' + sub_ip + "|" + "1", ] 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) 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) 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