def test_add_three_subscribers(self): """ Add flows for two subscribers """ imsi_1 = 'IMSI010000000088888' imsi_2 = 'IMSI010000111111118' imsi_3 = 'IMSI010002222222222' mac_1 = '5e:cc:cc:b1:49:4b' mac_2 = '5e:a:cc:af:aa:fe' mac_3 = '5e:bb:cc:aa:aa:fe' # Add subscriber with UE MAC address self.check_quota_controller.update_subscriber_quota_state( [ SubscriberQuotaUpdate( sid=SubscriberID(id=imsi_1), mac_addr=mac_1, update_type=SubscriberQuotaUpdate.NO_QUOTA), SubscriberQuotaUpdate( sid=SubscriberID(id=imsi_2), mac_addr=mac_2, update_type=SubscriberQuotaUpdate.NO_QUOTA), SubscriberQuotaUpdate( sid=SubscriberID(id=imsi_3), mac_addr=mac_3, update_type=SubscriberQuotaUpdate.VALID_QUOTA), ] ) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, include_stats=False) with snapshot_verifier: wait_after_send(self.testing_controller)
def test_invalid_subscriber(self): """ Try to apply an invalid policy to a subscriber, should log and error Assert: Only 1 flow gets added to the table (drop flow) """ fake_controller_setup(self.enforcement_controller) imsi = 'IMSI000000000000001' sub_ip = '192.168.128.45' flow_list = [ FlowDescription(match=FlowMatch( ip_src=convert_ipv4_str_to_ip_proto('9999.0.0.0/24')), action=FlowDescription.DENY) ] policy = PolicyRule(id='invalid', priority=2, flow_list=flow_list) invalid_sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._tbl_num).add_dynamic_rule(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( invalid_sub_context.cfg).build_requests(), self.testing_controller) flow_query = FlowQuery(self._tbl_num, self.testing_controller) num_flows_start = len(flow_query.lookup()) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with isolator, invalid_sub_context, snapshot_verifier: wait_after_send(self.testing_controller) num_flows_final = len(flow_query.lookup()) self.assertEqual(num_flows_final - num_flows_start, 0)
def test_uplink_to_ue_arp_router_mode(self): """ Verify that a UPLINK->UE arp request with IMSI set is properly matched """ pkt_sender = ScapyPacketInjector(self.IFACE) arp_packet = ARPPacketBuilder() \ .set_ether_layer(self.UE_MAC, self.OTHER_MAC) \ .set_arp_layer(self.UE_IP) \ .set_arp_hwdst(self.UE_MAC) \ .set_arp_src(self.OTHER_MAC, self.OTHER_IP) \ .build() dlink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \ .set_eth_match(eth_dst=self.UE_MAC, eth_src=self.OTHER_MAC) \ .set_reg_value(DIRECTION_REG, Direction.IN) \ .set_reg_value(IMSI_REG, 123) \ .build_requests() isolator = RyuDirectTableIsolator(dlink_args, self.testing_controller) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with isolator, snapshot_verifier: pkt_sender.send(arp_packet, count=4) wait_after_send(self.testing_controller) clean_to_ip_blocks_list()
def test_ue_to_uplink_arp(self): """ Verify that a UE->UPLINK arp request is dropped MME would not set IMSI reg """ pkt_sender = ScapyPacketInjector(self.IFACE) arp_packet = ARPPacketBuilder() \ .set_ether_layer(self.OTHER_MAC, self.UE_MAC) \ .set_arp_layer(self.OTHER_IP) \ .set_arp_hwdst(self.OTHER_MAC) \ .set_arp_src(self.UE_MAC, self.UE_IP) \ .build() uplink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \ .set_eth_match(eth_src=self.UE_MAC, eth_dst=self.OTHER_MAC) \ .set_reg_value(DIRECTION_REG, Direction.OUT) \ .build_requests() isolator = RyuDirectTableIsolator(uplink_args, self.testing_controller) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with isolator, snapshot_verifier: pkt_sender.send(arp_packet, count=4) wait_after_send(self.testing_controller)
def test_mtr_arp(self): """ Verify that a MTR arp request is handled in ARP responder """ pkt_sender = ScapyPacketInjector(self.IFACE) arp_packet = ARPPacketBuilder() \ .set_ether_layer(self.OTHER_MAC, self.MAC_DEST) \ .set_arp_layer(self.MTR_IP) \ .set_arp_hwdst(self.OTHER_MAC) \ .set_arp_src(self.UE_MAC, self.UE_IP) \ .build() uplink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \ .set_eth_type_arp() \ .set_reg_value(DIRECTION_REG, Direction.IN) \ .build_requests() isolator = RyuDirectTableIsolator(uplink_args, self.testing_controller) time.sleep(1) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with isolator, snapshot_verifier: pkt_sender.send(arp_packet, count=4) wait_after_send(self.testing_controller)
def test_stray_arp_drop(self): """ Verify that an arp that neither UE->UPLINK nor UPLINK->UE is dropped """ pkt_sender = ScapyPacketInjector(self.IFACE) arp_packet = ARPPacketBuilder() \ .set_ether_layer('11:11:11:11:11:1', self.OTHER_MAC) \ .set_arp_layer(self.OTHER_IP) \ .set_arp_hwdst(self.OTHER_MAC) \ .set_arp_src('22:22:22:22:22:22', '1.1.1.1') \ .build() uplink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \ .set_eth_match(eth_dst='11:11:11:11:11:1', eth_src=self.OTHER_MAC) \ .set_reg_value(DIRECTION_REG, Direction.OUT) \ .build_requests() isolator = RyuDirectTableIsolator(uplink_args, self.testing_controller) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with isolator, snapshot_verifier: pkt_sender.send(arp_packet, count=4) wait_after_send(self.testing_controller)
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_ipv6_flows(self): """ Verify that a UPLINK->UE arp request is properly matched """ ll_addr = get_if_hwaddr('testing_br') pkt_sender = ScapyPacketInjector(self.IFACE) pkt_rs = Ether(dst=self.OTHER_MAC, src=self.UE_MAC) pkt_rs /= IPv6( src='fe80:24c3:d0ff:fef3:9d21:4407:d337:1928', dst='ff02::2', ) pkt_rs /= ICMPv6ND_RS() pkt_rs /= ICMPv6NDOptSrcLLAddr(lladdr=ll_addr) pkt_ns = Ether(dst=self.OTHER_MAC, src=self.UE_MAC) pkt_ns /= IPv6( src='fe80::9d21:4407:d337:1928', dst='ff02::2', ) pkt_ns /= ICMPv6ND_NS(tgt='abcd:87:3::') pkt_ns /= ICMPv6NDOptSrcLLAddr(lladdr=ll_addr) ipv6_addr = 'ab22:5:6c:9:9d21:4407:d337:1928' interface = get_ipv6_interface_id(ipv6_addr) prefix = get_ipv6_prefix(ipv6_addr) self.service_manager.interface_to_prefix_mapper.save_prefix( interface, prefix, ) ulink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \ .set_eth_match(eth_dst=self.OTHER_MAC, eth_src=self.UE_MAC) \ .set_reg_value(DIRECTION_REG, Direction.OUT) \ .build_requests() isolator = RyuDirectTableIsolator(ulink_args, self.testing_controller) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, include_stats=False, ) with isolator, snapshot_verifier: pkt_sender.send(pkt_rs) pkt_sender.send(pkt_ns) wait_after_send(self.testing_controller, wait_time=5)
def test_traffic_flows(self): """ Attach the tunnel flows with UE IP address and send GTP and ARP traffic. """ # Need to delete all default flows in table 0 before # install the specific flows test case. self.test_detach_default_tunnel_flows() # Attach the tunnel flows towards UE. seid1 = 5000 self.classifier_controller.add_tunnel_flows(65525, 1, 1000, "192.168.128.30", self.EnodeB_IP, seid1) # Create a set of packets pkt_sender = ScapyPacketInjector(self.BRIDGE) eth = Ether(dst=self.MAC_1, src=self.MAC_2) ip = IP(src=self.Dst_nat, dst='192.168.128.30') o_udp = UDP(sport=2152, dport=2152) i_udp = UDP(sport=1111, dport=2222) i_tcp = TCP(seq=1, sport=1111, dport=2222) i_ip = IP(src='192.168.60.142', dst=self.EnodeB_IP) arp = ARP(hwdst=self.MAC_1, hwsrc=self.MAC_2, psrc=self.Dst_nat, pdst='192.168.128.30') gtp_packet_udp = eth / ip / o_udp / GTP_U_Header( teid=0x1, length=28, gtp_type=255) / i_ip / i_udp gtp_packet_tcp = eth / ip / o_udp / GTP_U_Header( teid=0x1, length=68, gtp_type=255) / i_ip / i_tcp arp_packet = eth / arp # Check if these flows were added (queries should return flows) flow_queries = [ FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(tunnel_id=1, in_port=32768)), FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(ipv4_dst='192.168.128.30')) ] # =========================== Verification =========================== # Verify 5 flows installed for classifier table (3 pkts matched) flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), 3, 5), FlowTest(flow_queries[0], 0, 1), ], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with flow_verifier, snapshot_verifier: pkt_sender.send(gtp_packet_udp) pkt_sender.send(gtp_packet_tcp) pkt_sender.send(arp_packet) flow_verifier.verify()
def test_add_valid_quota_subscriber(self): """ Add flows for two subscribers """ imsi_1 = 'IMSI010000000088888' mac_1 = '5e:cc:cc:b1:49:4b' # Add subscriber with UE MAC address """ self.check_quota_controller.update_subscriber_quota_state( SubscriberQuotaUpdate( sid=SubscriberID(id=imsi_1), mac_addr=mac_1, update_type=SubscriberQuotaUpdate.VALID_QUOTA)) wait_after_send(self.testing_controller) assert_bridge_snapshot_match(self, self.BRIDGE, self.service_manager)
def test_subscriber_restrict_policy(self): """ Add restrict policy to subscriber, send 4096 packets Assert: Packets are properly matched with the 'restrict_match' policy Send /20 (4096) packets, match /16 (256) packets """ fake_controller_setup(self.gy_controller) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list1 = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('8.8.8.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies = [ VersionedPolicy( rule=PolicyRule(id='restrict_match', priority=2, flow_list=flow_list1), version=1, ) ] pkts_matched = 256 pkts_sent = 4096 # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.gy_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('8.8.8.8', 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, include_stats=False) with isolator, sub_context, flow_verifier, snapshot_verifier: pkt_sender.send(packet)
def test_add_two_subscribers(self): """ Add UE MAC flows for two subscribers """ imsi_1 = 'IMSI010000000088888' imsi_2 = 'IMSI010000000099999' other_mac = '5e:cc:cc:b1:aa:aa' # Add subscriber with UE MAC address """ self.ue_mac_controller.add_ue_mac_flow(imsi_1, self.UE_MAC_1) self.ue_mac_controller.add_ue_mac_flow(imsi_2, self.UE_MAC_2) # Create a set of packets pkt_sender = ScapyPacketInjector(self.BRIDGE) # Only send downlink as the pkt_sender sends pkts from in_port=LOCAL downlink_packet1 = EtherPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .build() downlink_packet2 = EtherPacketBuilder() \ .set_ether_layer(self.UE_MAC_2, other_mac) \ .build() # Check if these flows were added (queries should return flows) flow_queries = [ FlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch(eth_dst=self.UE_MAC_1), ), FlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch(eth_dst=self.UE_MAC_2), ), ] # =========================== Verification =========================== # Verify 5 flows installed and 2 total pkts matched (one for each UE) flow_verifier = FlowVerifier( [ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), 2, 5) ] + [FlowTest(query, 1, 1) for query in flow_queries], lambda: wait_after_send(self.testing_controller), ) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with flow_verifier, snapshot_verifier: pkt_sender.send(downlink_packet1) pkt_sender.send(downlink_packet2) 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 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 packet_sender(): isolators = [ RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub).build_requests(), self.testing_controller, ) for sub in subs ] flow_query = FlowQuery(20, self.testing_controller) pkt_start = sum(flow.packets for flow in flow_query.lookup()) with ExitStack() as es: for iso in isolators: es.enter_context(iso) for packet in packets: pkt_sender.send(packet, count=count) wait_after_send(self.testing_controller) pkt_final = sum(flow.packets for flow in flow_query.lookup()) return pkt_final - pkt_start
def test_passthrough_rules(self): """ Add UE MAC flows for two subscribers """ imsi_1 = 'IMSI010000000088888' other_mac = '5e:cc:cc:b1:aa:aa' # Add subscriber with UE MAC address """ self.ue_mac_controller.add_ue_mac_flow(imsi_1, self.UE_MAC_1) # Create a set of packets pkt_sender = ScapyPacketInjector(self.BRIDGE) # Only send downlink as the pkt_sender sends pkts from in_port=LOCAL downlink_packet1 = EtherPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .build() dhcp_packet = UDPPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .set_ip_layer('151.42.41.122', '1.1.1.1') \ .set_udp_layer(67, 68) \ .build() dns_packet = UDPPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .set_ip_layer('151.42.41.122', '1.1.1.1') \ .set_udp_layer(53, 32795) \ .build() # Check if these flows were added (queries should return flows) flow_queries = [ FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(eth_dst=self.UE_MAC_1)) ] # =========================== Verification =========================== # Verify 8 flows installed for ue_mac table (3 pkts matched) # 4 flows installed for inout (3 pkts matched) # 2 fliws installed (2 pkts matches) flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), 3, 8), FlowTest(FlowQuery(self._ingress_tbl_num, self.testing_controller), 3, 4), FlowTest(FlowQuery(self._egress_tbl_num, self.testing_controller), 2, 2), FlowTest(flow_queries[0], 3, 4), ], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with flow_verifier, snapshot_verifier: pkt_sender.send(downlink_packet1) pkt_sender.send(dhcp_packet) pkt_sender.send(dns_packet) flow_verifier.verify()
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 """ imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list1 = [FlowDescription( match=FlowMatch( ipv4_dst='45.10.0.0/24', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies = [ PolicyRule(id='simple_match', priority=2, flow_list=flow_list1) ] pkts_matched = 256 pkts_sent = 4096 self._static_rule_dict[policies[0].id] = policies[0] # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._tbl_num ).add_static_rule(policies[0].id) 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)) with isolator, sub_context, flow_verifier: pkt_sender.send(packet) flow_verifier.verify()
def test_add_three_subscribers(self): """ Add flows for two subscribers """ imsi_1 = 'IMSI010000000088888' imsi_2 = 'IMSI010000111111118' imsi_3 = 'IMSI010002222222222' mac_1 = '5e:cc:cc:b1:49:4b' mac_2 = '5e:a:cc:af:aa:fe' mac_3 = '5e:bb:cc:aa:aa:fe' # Add subscriber with UE MAC address """ self.check_quota_controller.update_subscriber_quota_state( SubscriberQuotaUpdate(sid=SubscriberID(id=imsi_1), mac_addr=mac_1, update_type=SubscriberQuotaUpdate.NO_QUOTA)) self.check_quota_controller.update_subscriber_quota_state( SubscriberQuotaUpdate(sid=SubscriberID(id=imsi_2), mac_addr=mac_2, update_type=SubscriberQuotaUpdate.NO_QUOTA)) self.check_quota_controller.update_subscriber_quota_state( SubscriberQuotaUpdate( sid=SubscriberID(id=imsi_3), mac_addr=mac_3, update_type=SubscriberQuotaUpdate.VALID_QUOTA)) wait_after_send(self.testing_controller) assert_bridge_snapshot_match(self, self.BRIDGE, self.service_manager) self.check_quota_controller.update_subscriber_quota_state( SubscriberQuotaUpdate(sid=SubscriberID(id=imsi_2), mac_addr=mac_2, update_type=SubscriberQuotaUpdate.TERMINATE)) self.check_quota_controller.update_subscriber_quota_state( SubscriberQuotaUpdate(sid=SubscriberID(id=imsi_3), mac_addr=mac_3, update_type=SubscriberQuotaUpdate.TERMINATE))
def test_traffic_paging_flow(self): """ Add paging flow in table 0 """ # Need to delete all default flows in table 0 before # install the specific flows test case. self.classifier_controller._delete_all_flows() ue_ip_addr = "192.168.128.30" self.classifier_controller.install_paging_flow( IPAddress(version=IPAddress.IPV4, address=ue_ip_addr.encode('utf-8')), 200, True) # Create a set of packets pkt_sender = ScapyPacketInjector(self.BRIDGE) eth = Ether(dst=self.MAC_1, src=self.MAC_2) ip = IP(src=self.Dst_nat, dst='192.168.128.30') o_udp = UDP(sport=2152, dport=2152) i_udp = UDP(sport=1111, dport=2222) i_tcp = TCP(seq=1, sport=1111, dport=2222) i_ip = IP(src='192.168.60.142', dst=self.EnodeB_IP) gtp_packet_udp = eth / ip / o_udp / GTP_U_Header( teid=0x1, length=28, gtp_type=255) / i_ip / i_udp gtp_packet_tcp = eth / ip / o_udp / GTP_U_Header( teid=0x1, length=68, gtp_type=255) / i_ip / i_tcp # Check if these flows were added (queries should return flows) flow_queries = [ FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(tunnel_id=1, in_port=32768)), FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(ipv4_dst='192.168.128.30')) ] # =========================== Verification =========================== # Verify 2 flows installed for classifier table (2 pkts matched) flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), 2, 2), ], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with flow_verifier, snapshot_verifier: pkt_sender.send(gtp_packet_udp) pkt_sender.send(gtp_packet_tcp) flow_verifier.verify()
def test_delete_one_subscriber(self): """ Delete one of the existing subscribers """ imsi_1 = 'IMSI010000000088888' other_mac = '5e:cc:cc:b1:aa:aa' # Delete subscriber with UE MAC_1 address self.ue_mac_controller.delete_ue_mac_flow(imsi_1, self.UE_MAC_1) # Create a set of packets pkt_sender = ScapyPacketInjector(self.BRIDGE) # Only send downlink as the pkt_sender sends pkts from in_port=LOCAL removed_ue_packet = EtherPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .build() remaining_ue_packet = EtherPacketBuilder() \ .set_ether_layer(self.UE_MAC_2, other_mac) \ .build() # Ensure the first query doesn't match anything # And the second query still does flow_queries = [ FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(eth_dst=self.UE_MAC_1)), FlowQuery(self._tbl_num, self.testing_controller, match=MagmaMatch(eth_dst=self.UE_MAC_2)) ] # =========================== Verification =========================== # Verify 9 flows installed and 1 total pkt matched flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), 1, 9), FlowTest(flow_queries[0], 0, 0), FlowTest(flow_queries[1], 1, 4), ], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with flow_verifier, snapshot_verifier: pkt_sender.send(removed_ue_packet) pkt_sender.send(remaining_ue_packet) flow_verifier.verify()
def func(): wait_after_send(self.testing_controller) wait_for_enforcement_stats(self.enforcement_stats_controller, stat_names)
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 = [ PolicyRule(id='match', priority=2, flow_list=flow_list1), PolicyRule(id='no_match', priority=2, flow_list=flow_list2) ] pkts_sent = 42 self._static_rule_dict[policies[0].id] = policies[0] self._static_rule_dict[policies[1].id] = policies[1] # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext(imsi, sub_ip, self.enforcement_controller, self._tbl_num) \ .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) 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_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_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) 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).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, 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)) 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_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_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_passthrough_rules(self): """ Add UE MAC flows for two subscribers """ imsi_1 = 'IMSI010000000088888' other_mac = '5e:cc:cc:b1:aa:aa' cli_ip = '1.1.1.1' server_ip = '151.42.41.122' fake_mandatory_controller_setup(self.ingress_controller) fake_mandatory_controller_setup(self.middle_controller) fake_mandatory_controller_setup(self.egress_controller) # Add subscriber with UE MAC address """ self.ue_mac_controller.add_ue_mac_flow(imsi_1, self.UE_MAC_1) # Create a set of packets pkt_sender = ScapyPacketInjector(self.BRIDGE) # Only send downlink as the pkt_sender sends pkts from in_port=LOCAL downlink_packet1 = EtherPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .build() dhcp_packet = DHCPPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .set_ip_layer(server_ip, cli_ip) \ .set_udp_layer(67, 68) \ .set_bootp_layer(2, cli_ip, server_ip, other_mac) \ .set_dhcp_layer([("message-type", "ack"), "end"]) \ .build() dns_packet = UDPPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .set_ip_layer('151.42.41.122', '1.1.1.1') \ .set_udp_layer(53, 32795) \ .build() arp_packet = ARPPacketBuilder() \ .set_ether_layer(self.UE_MAC_1, other_mac) \ .set_arp_layer('1.1.1.1') \ .set_arp_hwdst(self.UE_MAC_1) \ .set_arp_src(other_mac, '1.1.1.12') \ .build() # Check if these flows were added (queries should return flows) flow_queries = [ FlowQuery( self._tbl_num, self.testing_controller, match=MagmaMatch(eth_dst=self.UE_MAC_1), ), ] # =========================== Verification =========================== # Verify 3 flows installed for ue_mac table (4 pkts matched) # 2 flows installed for ingress (4 pkts matched) # 2 flows installed for egress(3 pkts matches) flow_verifier = FlowVerifier( [ FlowTest( FlowQuery( self._tbl_num, self.testing_controller, ), 4, 3, ), FlowTest( FlowQuery( self._ingress_tbl_num, self.testing_controller, ), 4, 2, ), FlowTest( FlowQuery( self._egress_tbl_num, self.testing_controller, ), 3, 2, ), FlowTest(flow_queries[0], 4, 1), ], lambda: wait_after_send(self.testing_controller), ) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with flow_verifier, snapshot_verifier: pkt_sender.send(dhcp_packet) pkt_sender.send(downlink_packet1) pkt_sender.send(dns_packet) hub.sleep(3) pkt_sender.send(arp_packet) 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_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 = VersionedPolicy( rule=PolicyRule( id='redir_ip_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=0, server_address=redirect_ip, ), ), version=1, ) # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._tbl_num, ).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() # 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( ip_dst=convert_ipv4_str_to_ip_proto(redirect_ip), direction=FlowMatch.UPLINK, ), ), ) permit_inbound = FlowQuery( self._tbl_num, self.testing_controller, match=flow_match_to_magma_match( FlowMatch( ip_src=convert_ipv4_str_to_ip_proto(redirect_ip), direction=FlowMatch.DOWNLINK, ), ), ) learn_action_flow = flow_match_to_magma_match( FlowMatch( ip_proto=6, direction=FlowMatch.DOWNLINK, ip_src=convert_ipv4_str_to_ip_proto(self.BRIDGE_IP_ADDRESS), ip_dst=convert_ipv4_str_to_ip_proto(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_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)