Пример #1
0
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])
Пример #2
0
def test_tracing_with_limit():
    """
    Title: Tracing with a limit

    Scenario 1:
    When: a VM sends 20 ICMP echo requests over a trace request with limit 10
    Then: Trace data appears for the ingress and the egress host,
          but only for the first 10.
    Then: when disabled and reenabled, new trace data shows up
    """
    tracerequest = VTM.get_tracerequest('ping-trace-request-limited')
    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)
        for i in range(0, 20):
            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 172.16.2.1 and icmp',
                                                    within_sec(10)))
            f1 = sender.ping_ipv4_addr('172.16.2.1')
            wait_on_futures([f1, f2, f3])

        time.sleep(5)

        flowtraces = get_flow_traces(tracerequest.get_id())
        assert (len(flowtraces) == 10)

        # ensure both packets were traced on both hosts
        for i in range(0, 10):
            assert(len(get_hosts(tracerequest.get_id(), flowtraces[i])) == 2)

        tracerequest.set_enabled(False)
        tracerequest.set_enabled(True)

        time.sleep(5)

        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 172.16.2.1 and icmp',
                                                within_sec(10)))
        f1 = sender.ping_ipv4_addr('172.16.2.1')
        wait_on_futures([f1, f2, f3])

        time.sleep(5)

        flowtraces = get_flow_traces(tracerequest.get_id())
        assert (len(flowtraces) == 11)
    finally:
        unset_filters('router-000-001')
        tracerequest.set_enabled(False)
Пример #3
0
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])
Пример #4
0
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])
Пример #5
0
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])
Пример #6
0
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])
Пример #7
0
def test_tracing_with_limit():
    """
    Title: Tracing with a limit

    Scenario 1:
    When: a VM sends 20 ICMP echo requests over a trace request with limit 10
    Then: Trace data appears for the ingress and the egress host,
          but only for the first 10.
    Then: when disabled and reenabled, new trace data shows up
    """
    tracerequest = VTM.get_tracerequest('ping-trace-request-limited')
    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)
        for i in range(0, 20):
            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 172.16.2.1 and icmp',
                                                    within_sec(10)))
            f1 = sender.ping_ipv4_addr('172.16.2.1')
            wait_on_futures([f1, f2, f3])

        time.sleep(5)

        flowtraces = get_flow_traces(tracerequest.get_id())
        assert (len(flowtraces) == 10)

        # ensure both packets were traced on both hosts
        for i in range(0, 10):
            assert(len(get_hosts(tracerequest.get_id(), flowtraces[i])) == 2)

        tracerequest.set_enabled(False)
        tracerequest.set_enabled(True)

        time.sleep(5)

        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 172.16.2.1 and icmp',
                                                within_sec(10)))
        f1 = sender.ping_ipv4_addr('172.16.2.1')
        wait_on_futures([f1, f2, f3])

        time.sleep(5)

        flowtraces = get_flow_traces(tracerequest.get_id())
        assert (len(flowtraces) == 11)
    finally:
        unset_filters('router-000-001')
        tracerequest.set_enabled(False)
Пример #8
0
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])
Пример #9
0
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])
Пример #10
0
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)))
Пример #11
0
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])
Пример #12
0
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])
Пример #13
0
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])
Пример #14
0
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)
Пример #15
0
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])
Пример #16
0
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])
Пример #17
0
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])
Пример #18
0
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])
Пример #19
0
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)
Пример #20
0
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])
Пример #21
0
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])
Пример #22
0
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])
Пример #23
0
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])
Пример #24
0
def check_return_flow(src_vm, dst_vm, snat_ip, snat_port, dst_port, src_port):
    # And expect: Both vms receive 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])
Пример #25
0
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])
Пример #26
0
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])
Пример #27
0
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])
Пример #28
0
def check_return_flow(src_vm, dst_vm, snat_ip, snat_port, dst_port, src_port):
    # And expect: Both vms receive 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])
Пример #29
0
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')
Пример #30
0
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')
Пример #31
0
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:
        LOG.warn("Oops, sending ARP from the receiver VM failed.")
Пример #32
0
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])
Пример #33
0
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])
Пример #34
0
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.')
Пример #35
0
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])
Пример #36
0
def test_dnat_for_udp():
    """
    Title: Tests DNAT on UDP packets.

    Scenario:
    When: a VM sends UDP packets to an unassigned IP address.
    Then: the router performs DNAT on the message according to the rule chain
          set to the router,
    And: the UDP packets reach the receiver VM.
    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()

    f2 = async_assert_that(receiver, should_NOT_receive("dst host 172.16.2.1 and udp", within_sec(5)))
    f1 = sender.send_udp(router_mac, "100.100.100.100", 29, src_port=9, dst_port=9)
    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 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", "100.100.100.100", udp_src_port=9, udp_dst_port=9, timeout=within_sec(5)
        ),
    )
    f1 = sender.send_udp(router_mac, "100.100.100.100", 29, src_port=9, dst_port=9)
    wait_on_futures([f1, f2, f3])
Пример #37
0
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)

    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', suppress_failure=True)
    wait_on_futures([f1, f2])

    # Configure floating IP address with the router
    set_filters('router-000-001', 'pre_filter_floating_ip',
                'post_filter_floating_ip')

    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])
Пример #38
0
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])
Пример #39
0
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])
Пример #40
0
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])
Пример #41
0
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])
Пример #42
0
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])
Пример #43
0
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])
Пример #44
0
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])
Пример #45
0
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])
Пример #46
0
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])
Пример #47
0
def _send_icmp(sender, receiver, payload, target_ipv4,
               expect, expect_icmp_frag_needed=False):
    f1 = async_assert_that(receiver,
                           expect('dst host %s and icmp' % target_ipv4,
                                  within_sec(5)))

    f2 = _async_assert_receives_icmp_frag_needed(sender,
                                                 expect_icmp_frag_needed)

    time.sleep(1)

    f3 = sender.ping4(receiver, 0.5, 3, False, payload)

    wait_on_futures([f1, f2, f3])
Пример #48
0
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])
Пример #49
0
def assert_traffic_to(vip, assertion):
    backend_if = get_backend_if(1)
    source_ports = {NON_STICKY_VIP: 10108, STICKY_VIP:10109}
    source_port = source_ports[vip]
    recv_filter = 'dst host 10.0.2.1 and src port %s and tcp' % source_port

    dst_ip, dst_port = vip
    sender_router_port = VTM.get_router('router-000-001').get_port(1)
    sender_router_mac = sender_router_port.get_mn_resource().get_port_mac()
    # 41 bytes = 20 min IPv4 header + 20 min TCP header + 1 "trivial-test-udp"
    f1 = SENDER.send_tcp(sender_router_mac, dst_ip, 41,
                         src_port=source_port, dst_port=dst_port)
    f2 = async_assert_that(backend_if, assertion(recv_filter,
                                   within_sec(5)))
    wait_on_futures([f1, f2])
Пример #50
0
def test_tracing_egress_matching():
    """
    Title: Tracing egress matching

    Scenario 1:
    When: a VM sends ICMP echo request wait for echo response
    Then: Trace data appears for the ingress and the egress host
    """
    tracerequest = VTM.get_tracerequest("ping-trace-request")
    try:
        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 172.16.2.1 and icmp", within_sec(10)))
        f1 = sender.ping_ipv4_addr("172.16.2.1")
        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)
Пример #51
0
def _send_udp(sender, receiver, target_hw, target_ipv4, parms, payload,
              expect, expect_icmp_frag_needed=False):
    f1 = async_assert_that(receiver,
                           expect('dst host %s and udp' % target_ipv4,
                                  within_sec(5)))

    f2 = _async_assert_receives_icmp_frag_needed(sender,
                                                 expect_icmp_frag_needed)

    time.sleep(1)

    f3 = sender.send_packet(target_hw, target_ipv4, 'udp', parms, payload,
                            1, 3, False)

    wait_on_futures([f1, f2, f3])
Пример #52
0
def test_two_isolated_bridges():
    """
    Title: Two isolated bridges

    All traffic between two VMs in different and
    unconnected bridges should be independent, so
    receiver shouldn't get any packets
    """

    sender = BM.get_iface_for_port('bridge-000-001', 1)
    receiver = BM.get_iface_for_port('bridge-000-002', 1)

    f2 = async_assert_that(receiver, should_NOT_receive('', within_sec(5)))

    f1 = sender.ping4(receiver, 0.5, 3, False, 100)

    wait_on_futures([f1, f2])
Пример #53
0
def check_forward_flow(src_vm, dst_vm, fip, src_port, dst_port):
    # Expect: Both vms (with fip) 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}
Пример #54
0
def test_two_isolated_bridges():
    """
    Title: Two isolated bridges

    All traffic between two VMs in different and
    unconnected bridges should be independent, so
    receiver shouldn't get any packets
    """

    sender = BM.get_iface_for_port('bridge-000-001', 1)
    receiver = BM.get_iface_for_port('bridge-000-002', 1)

    f2 = async_assert_that(receiver,
                           should_NOT_receive('', within_sec(5)))

    f1 = sender.ping4(receiver, 0.5, 3, False, 100)

    wait_on_futures([f1, f2])
Пример #55
0
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])
Пример #56
0
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])
Пример #57
0
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])
Пример #58
0
def check_forward_flow(src_vm, dst_vm, fip, src_port, dst_port):
    # Expect: Both vms (with fip) 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}