def test_filter_ipv6(): """ Title: Filter IPv6 packets out on Bridge Scenario 1: When: there is no filter settings Then: IPv6 packets go through the bridge Scenario 2: When: the bridge has a chain in which there is a drop rule for IPv6 Then: IPv6 packets should not go through the bridge Scenario 3: When: the chain is removed from the bridge Then: IPv6 packets should go through again. """ iface1 = BM.get_iface_for_port('bridge-000-001', 1) iface2 = BM.get_iface_for_port('bridge-000-001', 2) iface1_hw_addr = iface1.interface['hw_addr'] iface2_hw_addr = iface2.interface['hw_addr'] ipv6_proto = "86:dd" ipv6_icmp = ("60:00:00:00:00:20:3a:ff:fe:80:00:00:00:00:00:00:1a:03:73:ff:" "fe:29:a9:b1:ff:02:00:00:00:00:00:00:00:00:00:01:ff:29:a9:b2:" "87:00:32:26:00:00:00:00:fe:80:00:00:00:00:00:00:1a:03:73:ff:" "fe:29:a9:b2:01:01:18:03:73:29:a9:b1") packet = '%s-%s-%s-%s' % (iface2_hw_addr, iface1_hw_addr, ipv6_proto, ipv6_icmp) rcv_filter = 'ether dst %s' % iface2_hw_addr # Sceneario 1: f1 = async_assert_that(iface2, receives(rcv_filter, within_sec(10))) # async_assert_that expects only 1 packet. Send only one, because the next # tcpdump might capture it (and fail the test) in case it takes some time # to arrive. # FIXME: make the tcpdump listener configurable f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2]) # Scenario 2: # setting chain and make sure it's dropped chain = VTM.get_chain('drop_ipv6') VTM.get_bridge('bridge-000-001').set_inbound_filter(chain) f1 = async_assert_that(iface2, should_NOT_receive( rcv_filter, within_sec(10))) f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2]) # Remove the filter and verify that packets go through again. VTM.get_bridge('bridge-000-001').set_inbound_filter(None) time.sleep(1) f1 = async_assert_that(iface2, receives(rcv_filter, within_sec(10))) f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2])
def test_dnat(): """ Title: Tests DNAT on ping messages. Scenario 1: When: a VM sends ICMP echo request with ping command to an unassigned IP address. Then: the router performs DNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) f2 = async_assert_that(receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2]) # Set DNAT rule chains to the router set_filters('router-000-001', 'pre_filter_001', 'post_filter_001') f2 = async_assert_that(receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f3 = async_assert_that(sender, receives('src host 100.100.100.100 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2, f3])
def test_snat(): """ Title: Tests SNAT on ping messages. Scenario: When: a VM sends ICMP echo request with ping command to a different subnet, Then: the router performs SNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, with src address NATted, And: the ping command succeeds. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) # No SNAT configured. Should not receive SNATed messages. f2 = async_assert_that(receiver, should_NOT_receive('src host 172.16.1.100 and icmp', within_sec(5))) f1 = sender.ping4(receiver) wait_on_futures([f1, f2]) # Set SNAT rule chains to the router set_filters('router-000-001', 'pre_filter_002', 'post_filter_002') # The receiver should receive SNATed messages. f2 = async_assert_that(receiver, receives('src host 172.16.1.100 and icmp', within_sec(5))) f3 = async_assert_that(sender, receives('dst host 172.16.1.1 and icmp', within_sec(5))) f1 = sender.ping4(receiver) wait_on_futures([f1, f2, f3])
def test_dnat(): """ Title: Tests DNAT on ping messages. Scenario 1: When: a VM sends ICMP echo request with ping command to an unassigned IP address. Then: the router performs DNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) f2 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2]) # Set DNAT rule chains to the router set_filters('router-000-001', 'pre_filter_001', 'post_filter_001') f2 = async_assert_that( receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f3 = async_assert_that( sender, receives('src host 100.100.100.100 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2, f3])
def test_filter_ipv6(): """ Title: Filter IPv6 packets out on Bridge Scenario 1: When: there is no filter settings Then: IPv6 packets go through the bridge Scenario 2: When: the bridge has a chain in which there is a drop rule for IPv6 Then: IPv6 packets should not go through the bridge Scenario 3: When: the chain is removed from the bridge Then: IPv6 packets should go through again. """ iface1 = BM.get_iface_for_port('bridge-000-001', 1) iface2 = BM.get_iface_for_port('bridge-000-001', 2) iface1_hw_addr = iface1.interface['hw_addr'] iface2_hw_addr = iface2.interface['hw_addr'] ipv6_proto = "86:dd" ipv6_icmp = ("60:00:00:00:00:20:3a:ff:fe:80:00:00:00:00:00:00:1a:03:73:ff:" "fe:29:a9:b1:ff:02:00:00:00:00:00:00:00:00:00:01:ff:29:a9:b2:" "87:00:32:26:00:00:00:00:fe:80:00:00:00:00:00:00:1a:03:73:ff:" "fe:29:a9:b2:01:01:18:03:73:29:a9:b1") packet = '%s-%s-%s-%s' % (iface2_hw_addr, iface1_hw_addr, ipv6_proto, ipv6_icmp) rcv_filter = 'ether dst %s' % iface2_hw_addr # Sceneario 1: f1 = async_assert_that(iface2, receives(rcv_filter, within_sec(10))) # async_assert_that expects only 1 packet. Send only one, because the next # tcpdump might capture it (and fail the test) in case it takes some time # to arrive. # FIXME: make the tcpdump listener configurable f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2]) # Scenario 2: # setting chain and make sure it's dropped chain = VTM.get_chain('drop_ipv6') VTM.get_bridge('bridge-000-001').set_inbound_filter(chain) f1 = async_assert_that(iface2, should_NOT_receive(rcv_filter, within_sec(10))) f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2]) # Remove the filter and verify that packets go through again. VTM.get_bridge('bridge-000-001').set_inbound_filter(None) time.sleep(1) f1 = async_assert_that(iface2, receives(rcv_filter, within_sec(10))) f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2])
def test_dst_mac_masking(): """ Title: Test destination MAC masking in chain rules Scenario 1: When: There's a rule dropping any traffic with the multicast bit on Then: Multicast traffic is blocked and unicast traffic goes through Scenario 2: When: There's a rule dropping any traffic with the multicast bit off Then: Multicast traffic goes through and unicast traffic is blocked """ bridge = VTM.get_bridge('bridge-000-001') if1 = BM.get_iface_for_port('bridge-000-001', 1) if2 = BM.get_iface_for_port('bridge-000-001', 2) if1_hw_addr = if1.get_mac_addr() # interface['hw_addr'] if2_hw_addr = if2.get_mac_addr() # interface['hw_addr'] if2_ip_addr = if2.get_ip() rcv_filter = 'udp and ether src %s' % if1_hw_addr bridge.set_inbound_filter(VTM.get_chain('drop_multicast')) # Send a frame to an arbitrary multicast address. Bridge doesn't # recognize it and will try to flood it to the other port, but the # masked MAC rule should drop it since it has the multicast bit set. f1 = async_assert_that(if2, should_NOT_receive(rcv_filter, within_sec(10))) f2 = if1.send_udp("01:23:45:67:89:ab", if2_ip_addr) wait_on_futures([f1, f2]) # If2's actual MAC address should work, since it doesn't have the bit set. f1 = async_assert_that(if2, receives(rcv_filter, within_sec(10))) f2 = if1.send_udp(if2_hw_addr, if2_ip_addr) wait_on_futures([f1, f2]) # Change to the chain that allows only multicast addresses. bridge.set_inbound_filter(VTM.get_chain('allow_only_multicast')) # Send another frame to the multicast address. Bridge doesn't # recognize it and will try to flood it to the other port. This # time the rule should allow it through. f1 = async_assert_that(if2, receives(rcv_filter, within_sec(10))) f2 = if1.send_udp("01:23:45:67:89:ab", if2_ip_addr) wait_on_futures([f1, f2]) # If2's actual MAC address should be blocked, since it doesn't # have the multicast bit set. f1 = async_assert_that(if2, should_NOT_receive(rcv_filter, within_sec(10))) f2 = if1.send_udp(if2_hw_addr, if2_ip_addr) wait_on_futures([f1, f2])
def send_udp(sender, receiver, hw_dst, dst_p, src_p, mirror=None): sender.get_mac_addr() sender.get_ip() ip_dst = receiver.get_ip() udp_filter = "dst host %s and dst port %d" % (ip_dst, dst_p) futures = [] futures.append(async_assert_that(receiver, receives(udp_filter, within_sec(15)))) if mirror is not None: futures.append(async_assert_that(mirror, receives(udp_filter, within_sec(15)))) sender.send_udp(hw_dst, ip_dst, src_port=src_p, dst_port=dst_p) wait_on_futures(futures)
def test_mac_learning(): """ Title: Bridge mac learning Scenario 1: When: the destination ethernet address has never been seen before. Then: the bridge should flood the ethernet unicast Scenario 2: When: the destination ethernet address has been seen before. Then: the bridge should not flood the ethernet frame, instaed it should forward to only the port that is connected to the interface with the mac address. """ sender = BM.get_iface_for_port('bridge-000-001', 1) iface_with_the_hw_addr = BM.get_iface_for_port('bridge-000-001', 2) iface_x = BM.get_iface_for_port('bridge-000-001', 3) hw_addr = iface_with_the_hw_addr.get_mac_addr() match_on_the_hw_addr = 'ether dst ' + hw_addr ethernet_unicast_to_the_hw_addr = '%s-7e:1f:ff:ff:ff:ff-aa:bb' % (hw_addr) # Scenario 1: # Both interfaces should get the frname as the bridge should flood it. f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that(iface_x, receives(match_on_the_hw_addr, within_sec(5))) time.sleep(1) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=3) wait_on_futures([f1, f2]) # Scenario 2: # Get the bridge to learn the mac address iface_with_the_hw_addr.ping4(sender, sync=True) time.sleep(1) # only iface_with_the_hw_addr should receives the ehternet unicast f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that(iface_x, should_NOT_receive(match_on_the_hw_addr, within_sec(5))) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=1) wait_on_futures([f1, f2])
def test_mac_learning(): """ Title: Bridge mac learning Scenario 1: When: the destination ethernet address has never been seen before. Then: the bridge should flood the ethernet unicast Scenario 2: When: the destination ethernet address has been seen before. Then: the bridge should not flood the ethernet frame, instaed it should forward to only the port that is connected to the interface with the mac address. """ sender = BM.get_iface_for_port('bridge-000-001', 1) iface_with_the_hw_addr = BM.get_iface_for_port('bridge-000-001', 2) iface_x = BM.get_iface_for_port('bridge-000-001', 3) hw_addr = iface_with_the_hw_addr.get_mac_addr() match_on_the_hw_addr = 'ether dst ' + hw_addr ethernet_unicast_to_the_hw_addr = '%s-7e:1f:ff:ff:ff:ff-aa:bb' % (hw_addr) # Scenario 1: # Both interfaces should get the frname as the bridge should flood it. f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that(iface_x, receives(match_on_the_hw_addr, within_sec(5))) time.sleep(1) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=3) wait_on_futures([f1, f2]) # Scenario 2: # Get the bridge to learn the mac address iface_with_the_hw_addr.ping4(sender, sync=True) time.sleep(1) # only iface_with_the_hw_addr should receives the ehternet unicast f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that( iface_x, should_NOT_receive(match_on_the_hw_addr, within_sec(5))) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=1) wait_on_futures([f1, f2])
def send_udp(sender, receiver, hw_dst, dst_p, src_p, mirror=None): sender.get_mac_addr() sender.get_ip() ip_dst = receiver.get_ip() udp_filter = "dst host %s and dst port %d" % (ip_dst, dst_p) futures = [] futures.append( async_assert_that(receiver, receives(udp_filter, within_sec(15)))) if mirror is not None: futures.append( async_assert_that(mirror, receives(udp_filter, within_sec(15)))) sender.send_udp(hw_dst, ip_dst, src_port=src_p, dst_port=dst_p) wait_on_futures(futures)
def test_fragmented_packets(): """ Title: L3 connectivity over bridge and router (MN-L3-ICMP-2) with large packets that will be fragmented Scenario 1: When: a VM sends a ICMP echo request with size >MTU uwing ping command to a different subnet Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # The receiver VM needs to send some frames so the MN Router learns # the VM's mac address. Otherwise this test would fail with binding2 # because the MidoNet Router forwards the ICMP with the previous mac # found in bindings1 in ethernet headers. # Issue: https://midobugs.atlassian.net/browse/MN-79 receiver.ping4(sender, 0.5, 3, True, 2000, do_arp=True) f1 = async_assert_that(receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver, 0.5, 3, False, 2000) wait_on_futures([f1, f2])
def _ping_from_mn(midoVmIface, exHostIface, count=3, do_arp=False): f1 = async_assert_that(exHostIface, receives('dst host 172.16.0.224 and icmp', within_sec(20))) f2 = midoVmIface.ping4(exHostIface, count=count, do_arp=do_arp) wait_on_futures([f1, f2])
def _ping_from_mn(midoVmIface, exHostIface, count=3, do_arp=False): f1 = async_assert_that( exHostIface, receives('dst host 172.16.0.224 and icmp', within_sec(20))) f2 = midoVmIface.ping4(exHostIface, count=count, do_arp=do_arp) wait_on_futures([f1, f2])
def _ping_to_mn(midoVmIface, exHostIface, count=3, do_arp=False): exHostIface.clear_arp() f1 = async_assert_that( midoVmIface, receives('dst host 172.16.0.1 and icmp', within_sec(5))) f2 = exHostIface.ping4(midoVmIface, count=count, do_arp=do_arp) wait_on_futures([f1, f2])
def perf_flowstate(): """ Title: Run a 1 hour workload that generates a lot of flow state Send 100 UDP packets per second for an hour, changing the src and dst port for each packet. The topology is set up in such a way that both conntrack and NAT flow state is generated. """ global PARAMETER_FPS, PARAMETER_MINUTES sender = BM.get_interface_on_vport('port_1') receiver = BM.get_interface_on_vport('port_2') messages_per_second = PARAMETER_FPS delay = 1000000 / messages_per_second try: sender.execute("hping3 -q -2 -i u%d --destport ++0 %s" % (delay, VTM.get_fip_ip())) rcv_filter = 'udp and ip dst %s' % (receiver.get_ip()) # check that we are still receiving traffic every minute for 30 minutes for i in range(0, PARAMETER_MINUTES): assert_that(receiver, receives(rcv_filter, within_sec(60))) time.sleep(60) finally: sender.execute("pkill hping3")
def _async_assert_receives_icmp_frag_needed(sender, should_receive): icmp_filter = 'icmp[icmptype] == icmp-unreach and icmp[icmpcode] == 4' if should_receive: return async_assert_that(sender, receives(icmp_filter, within_sec(5))) else: return async_assert_that( sender, should_NOT_receive(icmp_filter, within_sec(5)))
def test_fragmented_packets(): """ Title: L3 connectivity over bridge and router (MN-L3-ICMP-2) with large packets that will be fragmented Scenario 1: When: a VM sends a ICMP echo request with size >MTU uwing ping command to a different subnet Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # The receiver VM needs to send some frames so the MN Router learns # the VM's mac address. Otherwise this test would fail with binding2 # because the MidoNet Router forwards the ICMP with the previous mac # found in bindings1 in ethernet headers. # Issue: https://midobugs.atlassian.net/browse/MN-79 receiver.ping4(sender, 0.5, 3, True, 2000, do_arp=True) f1 = async_assert_that( receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver, 0.5, 3, False, 2000) wait_on_futures([f1, f2])
def _ping_to_mn(midoVmIface, exHostIface, count=3, do_arp=False): exHostIface.clear_arp() f1 = async_assert_that(midoVmIface, receives('dst host 172.16.0.1 and icmp', within_sec(5))) f2 = exHostIface.ping4(midoVmIface, count=count, do_arp=do_arp) wait_on_futures([f1, f2])
def check_return_flow(src_vm, dst_vm, snat_ip, snat_port, dst_port, src_port): # And expect: Internal VM receives return traffic recv_filter = 'udp and port %d and ip dst %s' % (dst_port, dst_vm.get_ip()) f = async_assert_that(dst_vm, receives(recv_filter, within_sec(10))) # When: sending return flows src_vm.execute('hping3 -c 1 -q -2 -s %s -p %s %s' % (src_port, snat_port, snat_ip)) wait_on_futures([f])
def test_icmp_autobind_vm_in_binding(): vm1 = BM2.get_interface_on_vport('port1') vm2 = BM2.get_interface_on_vport('port2') # Test ping works f1 = async_assert_that(vm2, receives('dst host %s and icmp' % vm2.get_ip(), within_sec(10))) f2 = vm1.ping4(vm2) wait_on_futures([f1, f2])
def _async_assert_receives_icmp_frag_needed(sender, should_receive): icmp_filter = 'icmp[icmptype] == icmp-unreach and icmp[icmpcode] == 4' if should_receive: return async_assert_that(sender, receives(icmp_filter, within_sec(5))) else: return async_assert_that(sender, should_NOT_receive(icmp_filter, within_sec(5)))
def test_tracing_egress_matching_over_nat(): """ Title: Tracing egress matching over nat Scenario 1: When: a VM sends ICMP echo request over nat wait for echo response Then: Trace data appears for the ingress and the egress host, but only as part of 2 flow traces (one for forward, one for return) """ unset_filters('router-000-001') tracerequest = VTM.get_tracerequest('ping-trace-request') try: set_filters('router-000-001', 'pre_filter_001', 'post_filter_001') tracerequest.set_enabled(True) time.sleep(5) flowtraces = get_flow_traces(tracerequest.get_id()) assert (len(flowtraces) == 0) sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) feed_receiver_mac(receiver) f2 = async_assert_that( receiver, receives('dst host 172.16.2.1 and icmp', within_sec(10))) f3 = async_assert_that( sender, receives('src host 100.100.100.100 and icmp', within_sec(10))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2, f3]) time.sleep(5) flowtraces = get_flow_traces(tracerequest.get_id()) assert (len(flowtraces) == 2) # ensure both packets were traced on both hosts assert (len(get_hosts(tracerequest.get_id(), flowtraces[0])) == 2) assert (len(get_hosts(tracerequest.get_id(), flowtraces[1])) == 2) finally: tracerequest.set_enabled(False) unset_filters('router-000-001')
def test_connection_tracking_by_network_addres(): ''' Title: Tests NW address based connection tracking. Scenario: When: A VM, supposedly inside a FW, sends UDP packets to another host, supposedly outside the FS, on the same bridge. And: The host outside the FW receives the UDP packets. Then: A connection-tracking-based peep hole is established. And: The outside host now can send UDP packets to the inside host. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Set a filtering rule based on ip address. set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_nw_in', 'connection_tracking_nw_out') # Send forward packets to set up a connection-tracking based peep hole in # the filter. port_num = get_random_port_num() f1 = async_assert_that( outside, receives('dst host 172.16.1.1 and udp', within_sec(5)), 'Outside host receives forward packets from inside.') f2 = inside.send_udp('aa:bb:cc:00:01:01', '172.16.1.1', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Verify the peep hole. f1 = async_assert_that( inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'Outside host can send packets to inside ' 'via a peep hole.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_connection_tracking_with_drop_by_dl(): ''' Title: Tests dl-based connection tracking. Scenario: When: A VM inside a FW sends UDP packets to a VM outside. And: The outside receives the UDP packets. Then: A connection-tracking-based peep hole is established. And: The outside now can send UDP packets to the inside. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Set a filtering rule based on mac addresses set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_dl_in', 'connection_tracking_dl_out') # Send forward packets to set up a connection-tracking based peep hole in # the filter. port_num = get_random_port_num() f1 = async_assert_that( outside, receives('dst host 172.16.1.1 and udp', within_sec(5)), 'The outside host receives forward packets ' 'from the inside.') f2 = inside.send_udp('aa:bb:cc:00:01:01', '172.16.1.1', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Verify the peep hole. f1 = async_assert_that( inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'The outside host can now send packets to the inside' 'via a peep hole.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_snat_for_udp(): """ Title: Tests SNAT on UDP packets. Scenario: When: a VM sends UDP packets to an unassigned IP address. Then: the router performs SNAT on the message according to the rule chain set to the router, And: the UDP packets reach the receiver VM, with src address NATted, And: because the UDP port is not open, the receiver VM returns ICMP error responses. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) # Target hardware is a router's incoming port. router_port = VTM.get_router('router-000-001').get_port(1) router_mac = router_port.get_mn_resource().get_port_mac() # No SNAT configured. Should not receive SNATed messages. f2 = async_assert_that( receiver, should_NOT_receive('src host 172.16.1.100 and udp', within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2]) # Set SNAT rule chains to the router set_filters('router-000-001', 'pre_filter_002', 'post_filter_002') # The receiver should receive SNATed messages. f2 = async_assert_that( receiver, receives('src host 172.16.1.100 and udp', within_sec(5))) # Sender should receive ICMP unreachable as the receiver port is not open. f3 = async_assert_that( sender, receives_icmp_unreachable_for_udp('172.16.1.1', '172.16.2.1', udp_src_port=9, udp_dst_port=65000, timeout=within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2, f3])
def test_flow_invalidation_on_mac_update(): """ Title: Flow invalidation, learning MACs The bridge learns the MACs from the traffic flowing by its ports. When the bridge learns a MAC that has 'moved' to another port, it should send traffic only to that port. """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 2) intruder = BM.get_iface_for_port('bridge-000-001', 3) receiver_MAC = receiver.get_mac_addr() frame = '%s-%s-aa:bb' % (receiver_MAC, receiver_MAC) capture = 'icmp and src host %s' % (sender.get_ip()) # Populate ARP table sender.execute('arp -s %s %s' % (receiver.get_ip(), receiver_MAC)) receiver.execute('arp -s %s %s' % (sender.get_ip(), sender.get_mac_addr())) # Trigger receiver MAC learning receiver.send_ether(frame) # First: packets go from sender to receiver f1 = async_assert_that(receiver, receives(capture, within_sec(5))) f2 = async_assert_that(intruder, should_NOT_receive(capture, within_sec(5))) f3 = sender.ping4(receiver) wait_on_futures([f1, f2, f3]) # Second: intruder claims to be receiver intruder.send_ether(frame) # Third: packets go from sender to intruder f1 = async_assert_that(receiver, should_NOT_receive(capture, within_sec(5))) f2 = async_assert_that(intruder, receives(capture, within_sec(5))) f3 = sender.ping4(receiver) wait_on_futures([f1, f2, f3])
def test_icmp_after_interface_recovery(): """ Title: ICMP reachability over bridge before and after interfaces go down Scenario 1: When: a VM sends ICMP echo request with ping command Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds Then: the receiver VM's tap goes down And: the ping command fails Then: the receiver VM's tap goes back up And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f1 = async_assert_that(receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_down() f1 = async_assert_that(receiver, should_NOT_receive('icmp', within_sec(5), on_host_interface(True))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_up() f1 = async_assert_that(receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def feed_receiver_mac(receiver): """Feeds the receiver's mac address to the MidoNet router.""" try: router_port = VTM.get_router('router-000-001').get_port(2) router_ip = router_port.get_mn_resource().get_port_address() receiver_ip = receiver.get_ip() f1 = async_assert_that(receiver, receives('dst host %s' % receiver_ip, within_sec(10))) receiver.send_arp_request(router_ip) wait_on_futures([f1]) except Exception: LOG.warn('Oops, sending ARP from the receiver VM failed.')
def feed_receiver_mac(receiver): """Feeds the receiver's mac address to the MidoNet router.""" try: router_port = VTM.get_router('router-000-001').get_port(2) router_ip = router_port.get_mn_resource().get_port_address() receiver_ip = receiver.get_ip() f1 = async_assert_that( receiver, receives('dst host %s' % receiver_ip, within_sec(10))) receiver.send_arp_request(router_ip) wait_on_futures([f1]) except Exception: LOG.warn('Oops, sending ARP from the receiver VM failed.')
def test_rule_changes(): """ Title: ICMP reachability over bridge before and after adding rule to drop IPv4 traffic. Scenario 1: When: A VM sends ICMP echo request with ping command Then: The receiver VM should receive the ICMP echo packet. And: The ping command succeeds Then: The receiver adds a rule blocking IPv4 traffic. And: The ping command fails Then: the receiver removes the rule And: The ping succeeds again. """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 2) # There are no filters, so the first ping should succeed. f1 = async_assert_that(receiver, receives('icmp', within_sec(5))) f2 = sender.ping4(receiver, do_arp=True) wait_on_futures([f1, f2]) # Add a filter dropping all IPv4 traffic to port 2. chain = VTM.get_chain('drop_ipv4') VTM.get_device_port('bridge-000-001', 2).set_outbound_filter(chain) # The second ping should not reach port 2. f1 = async_assert_that(receiver, should_NOT_receive('icmp', within_sec(5))) f2 = sender.ping4(receiver, do_arp=True) wait_on_futures([f1, f2]) # After removing the filter, ping should succeed again. VTM.get_device_port('bridge-000-001', 2).set_outbound_filter(None) f1 = async_assert_that(receiver, receives('icmp', within_sec(5))) f2 = sender.ping4(receiver, do_arp=True) wait_on_futures([f1, f2])
def run_garp_scenario(BM, sender_port, target_ip, enable_vip, disable_vip): vip1 = BM.get_interface_on_vport('port_int1') vip2 = BM.get_interface_on_vport('port_int2') sender = BM.get_interface_on_vport(sender_port) # allow sender to accept gratutious arps (only makes sense if on same network) sender.execute('bash -c "echo 1 > /proc/sys/net/ipv4/conf/%s/arp_accept"' % sender.get_ifname()) rcv_filter = 'icmp and ip src %s' % (sender.get_ip()) # noone responds initially f1 = async_assert_that(vip1, should_NOT_receive(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3]) # enable for vip1 enable_vip(vip1) disable_vip(vip2) f1 = async_assert_that(vip1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3]) # enable for vip2 enable_vip(vip2) disable_vip(vip1) f1 = async_assert_that(vip1, should_NOT_receive(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, receives(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3]) # enable for vip1 enable_vip(vip1) disable_vip(vip2) f1 = async_assert_that(vip1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3])
def test_floating_ip(): """ Title: Tests a floating IP. Scenario 1: When: a VM sends an ICMP echo request to a floating IP address (100.100.100.100). Then: the router performs DNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, And: the receiver sends back an ICMP reply with its original IP address as a source address. And: the router applies SNAT to the reply packet. And: the sender receives the reply with src address NATed to the floating IP address. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) f1 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(10))) sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1]) # Configure floating IP address with the router set_filters('router-000-001', 'pre_filter_floating_ip', 'post_filter_floating_ip') f1 = async_assert_that( receiver, receives('dst host 172.16.2.1 and icmp', within_sec(10))) f2 = async_assert_that( sender, receives('src host 100.100.100.100 and icmp', within_sec(10))) sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2])
def test_icmp_after_interface_recovery(): """ Title: ICMP reachability over bridge before and after interfaces go down Scenario 1: When: a VM sends ICMP echo request with ping command Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds Then: the receiver VM's tap goes down And: the ping command fails Then: the receiver VM's tap goes back up And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f1 = async_assert_that( receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_down() f1 = async_assert_that( receiver, should_NOT_receive('icmp', within_sec(5), on_host_interface(True))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_up() f1 = async_assert_that( receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_connection_tracking_with_drop_by_dl(): ''' Title: Tests dl-based connection tracking. Scenario: When: A VM inside a FW sends UDP packets to a VM outside. And: The outside receives the UDP packets. Then: A connection-tracking-based peep hole is established. And: The outside now can send UDP packets to the inside. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Set a filtering rule based on mac addresses set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_dl_in', 'connection_tracking_dl_out') # Send forward packets to set up a connection-tracking based peep hole in # the filter. port_num = get_random_port_num() f1 = async_assert_that(outside, receives('dst host 172.16.1.1 and udp', within_sec(5)), 'The outside host receives forward packets ' 'from the inside.') f2 = inside.send_udp('aa:bb:cc:00:01:01', '172.16.1.1', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Verify the peep hole. f1 = async_assert_that(inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'The outside host can now send packets to the inside' 'via a peep hole.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_connection_tracking_by_network_addres(): ''' Title: Tests NW address based connection tracking. Scenario: When: A VM, supposedly inside a FW, sends UDP packets to another host, supposedly outside the FS, on the same bridge. And: The host outside the FW receives the UDP packets. Then: A connection-tracking-based peep hole is established. And: The outside host now can send UDP packets to the inside host. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Set a filtering rule based on ip address. set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_nw_in', 'connection_tracking_nw_out') # Send forward packets to set up a connection-tracking based peep hole in # the filter. port_num = get_random_port_num() f1 = async_assert_that(outside, receives('dst host 172.16.1.1 and udp', within_sec(5)), 'Outside host receives forward packets from inside.') f2 = inside.send_udp('aa:bb:cc:00:01:01', '172.16.1.1', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Verify the peep hole. f1 = async_assert_that(inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'Outside host can send packets to inside ' 'via a peep hole.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_src_mac_masking(): """ Title: Test source MAC masking in chain rules Scenario 1: When: There's a rule dropping any traffic with an even source MAC Then: Traffic from if2 to if1 is blocked because if2's MAC ends with 2 And: Traffic from if1 to if2 goes through because if1's MAC ends with 1 FIXME: moving to the new bindings mechanisms should allow removing this restriction. Only running this with the one-host binding, because: 1. The multi-host binding breaks the assumptions that if1 will have an odd MAC address and if2 an even one. 2. This is basically just a sanity test to make sure dl_src_mask is wired up. Unit tests and test_dst_mac_masking provide enough coverage of the other aspects. 3. These tests are slow enough as it is. """ bridge = VTM.get_bridge('bridge-000-001') if1 = BM.get_iface_for_port('bridge-000-001', 1) if2 = BM.get_iface_for_port('bridge-000-001', 2) if1_hw_addr = if1.interface['hw_addr'] if2_hw_addr = if2.interface['hw_addr'] if1_ip_addr = if1.get_ip() if2_ip_addr = if2.get_ip() if1_rcv_filter = 'udp and ether dst %s' % if1_hw_addr if2_rcv_filter = 'udp and ether dst %s' % if2_hw_addr bridge.set_inbound_filter(VTM.get_chain('drop_even_src_mac')) # If2 has an even MAC (ends with 2), so traffic from if2 to if1 # should be dropped. f1 = async_assert_that(if1, should_NOT_receive(if1_rcv_filter, within_sec(5))) time.sleep(1) f2 = if2.send_udp(if1_hw_addr, if1_ip_addr, 41) wait_on_futures([f1, f2]) # If1 has an odd MAC (ends with 1), so traffic from if1 to if2 # should go through. f1 = async_assert_that(if2, receives(if2_rcv_filter, within_sec(5))) time.sleep(1) f2 = if1.send_udp(if2_hw_addr, if2_ip_addr, 41) wait_on_futures([f1, f2])
def test_floating_ip(): """ Title: Tests a floating IP. Scenario 1: When: a VM sends an ICMP echo request to a floating IP address (100.100.100.100). Then: the router performs DNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, And: the receiver sends back an ICMP reply with its original IP address as a source address. And: the router applies SNAT to the reply packet. And: the sender receives the reply with src address NATed to the floating IP address. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) f1 = async_assert_that(receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(10))) sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1]) # Configure floating IP address with the router set_filters('router-000-001', 'pre_filter_floating_ip', 'post_filter_floating_ip') f1 = async_assert_that(receiver, receives('dst host 172.16.2.1 and icmp', within_sec(10))) f2 = async_assert_that(sender, receives('src host 100.100.100.100 and icmp', within_sec(10))) sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2])
def test_snat(): """ Title: Tests SNAT on ping messages. Scenario: When: a VM sends ICMP echo request with ping command to a different subnet, Then: the router performs SNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, with src address NATted, And: the ping command succeeds. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) # No SNAT configured. Should not receive SNATed messages. f2 = async_assert_that( receiver, should_NOT_receive('src host 172.16.1.100 and icmp', within_sec(5))) f1 = sender.ping4(receiver) wait_on_futures([f1, f2]) # Set SNAT rule chains to the router set_filters('router-000-001', 'pre_filter_002', 'post_filter_002') # The receiver should receive SNATed messages. f2 = async_assert_that( receiver, receives('src host 172.16.1.100 and icmp', within_sec(5))) f3 = async_assert_that( sender, receives('dst host 172.16.1.1 and icmp', within_sec(5))) f1 = sender.ping4(receiver) wait_on_futures([f1, f2, f3])
def check_forward_flow(src_vm, dst_vm, fip, src_port, dst_port): # Expect: VM with fip to receive the packet recv_filter = 'udp and port %d and ip dst %s' % (dst_port, dst_vm.get_ip()) f = async_assert_that(dst_vm, receives(recv_filter, within_sec(10))) # When: Sending udp packet # src_vm (internal) -> dst_vm (fip) src_vm.execute('hping3 -c 1 -q -2 -s %s -p %s %s' % (src_port, dst_port, fip)) wait_on_futures([f]) # tcpdump format: # date net_proto src_ip.src_port > dst_ip.dst_port: transp_proto [...] output = dst_vm.get_last_tcpdump_output() snat_ip = output.split(' ')[2].rsplit('.', 1)[0] snat_port = output.split(' ')[2].rsplit('.', 1)[1] return {'ip': snat_ip, 'port': snat_port}
def test_icmp(): """ Title: ICMP reachability over bridge Scenario 1: When: a VM sends ICMP echo request with ping command Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f1 = async_assert_that(receiver, receives('dst host %s and icmp' % receiver.get_ip(), within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_fragmented_packets(): """ Title: Fragmented IP packets through a bridge Scenario 1: When: a VM sends large PING packets (> MTU) Then: the receiver should receive the ICMP echo packet And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f2 = async_assert_that( receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f1 = sender.ping4(receiver, 0.5, 3, False, 2000) wait_on_futures([f1, f2])
def test_icmp(): """ Title: ICMP reachability over bridge Scenario 1: When: a VM sends ICMP echo request with ping command Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f1 = async_assert_that( receiver, receives('dst host %s and icmp' % receiver.get_ip(), within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_snat_for_udp(): """ Title: Tests SNAT on UDP packets. Scenario: When: a VM sends UDP packets to an unassigned IP address. Then: the router performs SNAT on the message according to the rule chain set to the router, And: the UDP packets reach the receiver VM, with src address NATted, And: because the UDP port is not open, the receiver VM returns ICMP error responses. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) # Target hardware is a router's incoming port. router_port = VTM.get_router('router-000-001').get_port(1) router_mac = router_port.get_mn_resource().get_port_mac() # No SNAT configured. Should not receive SNATed messages. f2 = async_assert_that(receiver, should_NOT_receive('src host 172.16.1.100 and udp', within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2]) # Set SNAT rule chains to the router set_filters('router-000-001', 'pre_filter_002', 'post_filter_002') # The receiver should receive SNATed messages. f2 = async_assert_that(receiver, receives('src host 172.16.1.100 and udp', within_sec(5))) # Sender should receive ICMP unreachable as the receiver port is not open. f3 = async_assert_that(sender, receives_icmp_unreachable_for_udp( '172.16.1.1', '172.16.2.1', udp_src_port=9, udp_dst_port=65000, timeout=within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2, f3])
def test_filtering_by_network_address(): ''' Title: Tests packets filtering based on network address Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reaches the receiver. Then: Filtering rule chains based on network address (IP address) are set on the bridge port that the receiver host is connected to. And: The UDP packets from the same sender do NOT reach the receiver. ''' sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-001', 3) # Reset in/out-bound filters. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() # FIXME: do not use harcoded values! f1 = async_assert_that( receiver, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: receives UDP packets from sender.') f2 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Set a filtering rule based on network address. set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_nw_in', 'connection_tracking_nw_out') f1 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on IP address.') f2 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_icmp_topology_out_test_two_computes(): # Query resources created on the managers vm1 = PTM2.get_resource('vm1_host1') vm2 = PTM2.get_resource('vm2_host2') port1 = VTM2.get_resource('port1') port2 = VTM2.get_resource('port2') # Bind virtual and physical topology vm1.compute_host.bind_port(vm1, port1['port']['id']) vm2.compute_host.bind_port(vm2, port2['port']['id']) # Test ping works f1 = async_assert_that(vm2, receives('dst host %s and icmp' % vm2.get_ip(), within_sec(10))) f2 = vm1.ping4(vm2) wait_on_futures([f1, f2])
def test_fragmented_packets(): """ Title: Fragmented IP packets through a bridge Scenario 1: When: a VM sends large PING packets (> MTU) Then: the receiver should receive the ICMP echo packet And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f2 = async_assert_that(receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f1 = sender.ping4(receiver, 0.5, 3, False, 2000) wait_on_futures([f1, f2])
def test_filtering_by_dl(): ''' Title: Tests dl-based packet filtering. Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reach the receiver without filtering rule chains. Then: A filtering rule chain based on mac address is set on the bridge. And: UDP packets from the same host do NOT reach the same destination host. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Reset an in-bound filter. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() f1 = async_assert_that( inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: inside receives UDP packets from outside.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Set a filtering rule based on mac addresses set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_dl_in', 'connection_tracking_dl_out') f1 = async_assert_that( inside, should_NOT_receive('dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on mac address.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_ping_delete_port(): """ Title: L3 connectivity over bridge and router, then deletes a port and verifies that there is no connectivity. Implemented to cover the old DeletePortTest. Scenario 1: When: a VM sends ICMP echo request with ping command to a different subnet Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds When: the destination port on the router is deleted Then: the receiver VM should NOT receive the ICMP echo packet """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # The receiver VM needs to send some frames so the MN Router learns # the VM's mac address. Otherwise this test would fail with binding2 # because the MidoNet Router forwards the ICMP with the previous mac # found in bindings1 in ethernet headers. # Issue: https://midobugs.atlassian.net/browse/MN-79 receiver.ping4(sender) f1 = async_assert_that(receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) port = VTM.get_device_port('router-000-001', 2) port.destroy() f1 = async_assert_that(receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_ping_delete_port(): """ Title: L3 connectivity over bridge and router, then deletes a port and verifies that there is no connectivity. Implemented to cover the old DeletePortTest. Scenario 1: When: a VM sends ICMP echo request with ping command to a different subnet Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds When: the destination port on the router is deleted Then: the receiver VM should NOT receive the ICMP echo packet """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # The receiver VM needs to send some frames so the MN Router learns # the VM's mac address. Otherwise this test would fail with binding2 # because the MidoNet Router forwards the ICMP with the previous mac # found in bindings1 in ethernet headers. # Issue: https://midobugs.atlassian.net/browse/MN-79 receiver.ping4(sender) f1 = async_assert_that( receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) port = VTM.get_device_port('router-000-001', 2) port.destroy() f1 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_filtering_by_dl(): ''' Title: Tests dl-based packet filtering. Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reach the receiver without filtering rule chains. Then: A filtering rule chain based on mac address is set on the bridge. And: UDP packets from the same host do NOT reach the same destination host. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Reset an in-bound filter. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() f1 = async_assert_that( inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: inside receives UDP packets from outside.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Set a filtering rule based on mac addresses set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_dl_in', 'connection_tracking_dl_out') f1 = async_assert_that(inside, should_NOT_receive( 'dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on mac address.') f2 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_filtering_by_network_address(): ''' Title: Tests packets filtering based on network address Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reaches the receiver. Then: Filtering rule chains based on network address (IP address) are set on the bridge port that the receiver host is connected to. And: The UDP packets from the same sender do NOT reach the receiver. ''' sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-001', 3) # Reset in/out-bound filters. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() # FIXME: do not use harcoded values! f1 = async_assert_that(receiver, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: receives UDP packets from sender.') f2 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Set a filtering rule based on network address. set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_nw_in', 'connection_tracking_nw_out') f1 = async_assert_that(receiver, should_NOT_receive( 'dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on IP address.') f2 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])