Java tutorial
/* * Copyright 2014 Midokura SARL * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.midonet.brain.services.vxgw; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Collection; import java.util.Random; import java.util.UUID; import com.google.inject.Guice; import com.google.inject.Injector; import org.apache.commons.configuration.HierarchicalConfiguration; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import rx.Observable; import rx.Subscription; import org.midonet.brain.BrainTestUtils; import org.midonet.brain.configuration.MidoBrainConfig; import org.midonet.brain.southbound.vtep.VtepBroker; import org.midonet.brain.southbound.vtep.VtepConstants; import org.midonet.brain.southbound.vtep.VtepDataClient; import org.midonet.brain.southbound.vtep.VtepDataClientFactory; import org.midonet.brain.southbound.vtep.VtepException; import org.midonet.brain.southbound.vtep.VtepMAC; import org.midonet.cluster.DataClient; import org.midonet.cluster.data.Bridge; import org.midonet.cluster.data.TunnelZone; import org.midonet.cluster.data.VTEP; import org.midonet.cluster.data.VtepBinding; import org.midonet.cluster.data.host.Host; import org.midonet.midolman.host.state.HostZkManager; import org.midonet.midolman.serialization.SerializationException; import org.midonet.midolman.state.Directory; import org.midonet.midolman.state.StateAccessException; import org.midonet.midolman.state.ZookeeperConnectionWatcher; import org.midonet.packets.IPv4Addr; import org.midonet.util.functors.Callback; import mockit.Expectations; import mockit.Mocked; import mockit.integration.junit4.JMockit; import static org.junit.Assert.assertEquals; @RunWith(JMockit.class) public class VxLanFloodingProxyTest { private static final byte[] VTEP_MGMT_IP = { (byte) 192, (byte) 168 }; private static final byte[] HOST_IP = { (byte) 10, (byte) 2 }; private static final int VTEP_MGMT_PORT = 6632; private static final int VTEP_VNI = 10001; private DataClient midoClient; private ZookeeperConnectionWatcher zkConnWatcher; private HostZkManager hostZkManager; private static final class MockRandom extends Random { @Override public int nextInt(int n) { return n - 1; } } private static final Subscription emptySubscription = Observable.empty().subscribe(); @Mocked private VtepDataClient vtepClient; @Mocked private VtepDataClientFactory vtepDataClientFactory; @Mocked private MidoBrainConfig brainConfig; private VxLanGatewayService vxgwService; @Before public void setup() throws Exception { HierarchicalConfiguration config = new HierarchicalConfiguration(); BrainTestUtils.fillTestConfig(config); Injector injector = Guice.createInjector(BrainTestUtils.modules(config)); Directory directory = injector.getInstance(Directory.class); BrainTestUtils.setupZkTestDirectory(directory); midoClient = injector.getInstance(DataClient.class); zkConnWatcher = new ZookeeperConnectionWatcher(); hostZkManager = injector.getInstance(HostZkManager.class); vxgwService = new VxLanGatewayService(midoClient, vtepDataClientFactory, zkConnWatcher, brainConfig, new MockRandom()); } /** * This tests checks that there is no flooding proxy cleared or set in a * scenario with 1 tunnel zone, 1 VTEP, 1 host, and 0 bridges. All entities * exist before the starting the VXGW service. * * The VXGW should not clear or set a flooding proxy because there are no * logical switches, and the existing host is not alive. */ @Test public void testNoBridges(@Mocked final VtepBroker vtepBroker) throws Exception { new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; createHost(1); UUID tzId = createTunnelZone(1); createVtep(1, tzId); vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is no flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 host and 1 bridge. Because of the double * notification of a bridge creation, the VXGW will clear the flooding proxy * once. All entities exist before the starting the VXGW service. * * The VXGW should not set a flooding proxy, because there are no member * hosts in the tunnel zone, and the existing host is not alive. */ @Test public void testNoTunnelZoneMembership(@Mocked final VtepBroker vtepBroker) throws Exception { createHost(1); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is no flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 host and 1 bridge, and where the host is a * a member of the tunnel zone. Because of the double notification of a * bridge creation, the VXGW will clear the flooding proxy once. All * entities exist before the starting the VXGW service. * * The VXGW should not set a flooding proxy the existing host is not alive. */ @Test public void testExistingBridgeHostNotAlive(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); UUID tzId = createTunnelZone(1); addTunnelZoneMember(tzId, hostId); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is no flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 host and 1 bridge, and where the host is a * a member of the tunnel zone. Because of the double notification of a * bridge creation, the VXGW will clear the flooding proxy once. All * entities exist before the starting the VXGW service. * * The VXGW should not set a flooding proxy the existing host is not alive. */ @Test public void testExistingBridgeHostAlive(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); hostZkManager.makeAlive(hostId); UUID tzId = createTunnelZone(1); addTunnelZoneMember(tzId, hostId); final IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is no flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 host and 1 bridge. Because of the double * notification of a bridge creation, the VXGW will clear the flooding proxy * once. All entities exist before the starting the VXGW service, but the * host is added to the tunnel zone membership after the VXGW service * started. * * The VXGW should not set a flooding proxy, because the existing host is * not alive. */ @Test public void testTunnelZoneMembershipNotifyHostNotAlive(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); addTunnelZoneMember(tzId, hostId); assertEquals(vxgwService.getFloodingProxy(tzId), null); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 host and 1 bridge. Because of the double * notification of a bridge creation, the VXGW will clear the flooding proxy * once. All entities exist before the starting the VXGW service, but the * host is added to the tunnel zone membership after the VXGW service * started. * * The VXGW should set the host as a flooding proxy. */ @Test public void testTunnelZoneMembershipNotify(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); hostZkManager.makeAlive(hostId); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); addTunnelZoneMember(tzId, hostId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 host and 1 bridge. Because of the double * notification of a bridge creation, the VXGW will clear the flooding proxy * once. All entities exist before the starting the VXGW service, but the * host is set as alive after the VXGW service started. * * The VXGW service should only set a flooding proxy after the host is * alive. When the host is no longer alive, the VXGW service should remove * the flooding proxy. */ @Test public void testHostAliveNotify(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); addTunnelZoneMember(tzId, hostId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Clear flooding proxy. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); hostZkManager.makeAlive(hostId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); hostZkManager.makeNotAlive(hostId); assertEquals(vxgwService.getFloodingProxy(tzId), null); hostZkManager.makeAlive(hostId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is no flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 host and 1 bridge. All entities exist before * the starting the VXGW service. The host is a tunnel zone member and is * alive. * * The VXGW service should recompute the flooding proxy when the flooding * proxy weight has changed for a host. If the flooding proxy has not * changed no action is taken. However, if the flooding proxy has a weight * of zero (0), the host cannot longer be a flooding proxy. */ @Test public void testHostFloodingProxyChangedNotify(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); hostZkManager.makeAlive(hostId); addTunnelZoneMember(tzId, hostId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Clear flooding proxy. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.hostsSetFloodingProxyWeight(hostId, 2); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.hostsSetFloodingProxyWeight(hostId, 0); assertEquals(vxgwService.getFloodingProxy(tzId), null); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 2 hosts and 1 bridge. Because of the double * notification of a bridge creation, the VXGW will clear the flooding proxy * once. All entities exist before the starting the VXGW service, but the * hosts are set as alive after the VXGW service started. * * Both host have the default flooding proxy weight (1). The first alive * host should be selected as flooding proxy, and the flooding proxy should * change only when the host goes offline. */ @Test public void testTwoHostsAliveNotify(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId1 = createHost(1); UUID hostId2 = createHost(2); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); addTunnelZoneMember(tzId, hostId1); addTunnelZoneMember(tzId, hostId2); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Set flooding proxy to host 2. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(2).getAddress()))); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); hostZkManager.makeAlive(hostId1); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); hostZkManager.makeAlive(hostId2); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); hostZkManager.makeNotAlive(hostId1); assertEquals(vxgwService.getFloodingProxy(tzId), hostId2); hostZkManager.makeAlive(hostId1); assertEquals(vxgwService.getFloodingProxy(tzId), hostId2); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 2 hosts and 1 bridge. All entities exist before * the starting the VXGW service, but the hosts are set as alive after the * VXGW service started. * * Initially, both host have the default flooding proxy weight (1). * The second host increases its flooding proxy weight and it should be * selected as a flooding proxy. Then, the second host sets its flooding * proxy weight to zero, and the first host should be selected as a flooding * proxy. */ @Test public void testTwoHostsFloodingProxyWeightNotify(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId1 = createHost(1); UUID hostId2 = createHost(2); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); addTunnelZoneMember(tzId, hostId1); addTunnelZoneMember(tzId, hostId2); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Set flooding proxy to host 2. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(2).getAddress()))); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); hostZkManager.makeAlive(hostId1); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); hostZkManager.makeAlive(hostId2); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); midoClient.hostsSetFloodingProxyWeight(hostId2, 2); assertEquals(vxgwService.getFloodingProxy(tzId), hostId2); midoClient.hostsSetFloodingProxyWeight(hostId2, 0); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 hosts and 1 bridge. The host is created, added * to the tunnel zone and set as alive after the VXGW service started. * * The host should be set as a flooding proxy after set as live and a * member of the tunnel zone. */ @Test public void testHostLifecycle(@Mocked final VtepBroker vtepBroker) throws Exception { UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Clear flooding proxy. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), null); UUID hostId = createHost(1); assertEquals(vxgwService.getFloodingProxy(tzId), null); hostZkManager.makeAlive(hostId); assertEquals(vxgwService.getFloodingProxy(tzId), null); addTunnelZoneMember(tzId, hostId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.tunnelZonesDeleteMembership(tzId, hostId); assertEquals(vxgwService.getFloodingProxy(tzId), null); hostZkManager.makeNotAlive(hostId); assertEquals(vxgwService.getFloodingProxy(tzId), null); midoClient.hostsDelete(hostId); assertEquals(vxgwService.getFloodingProxy(tzId), null); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 hosts and 1 bridge. The bridge is created after * the VXGW service started. * * The tunnel zone state should always have the host set as the current * flooding proxy. However, the VTEP is configured with the flooding proxy * only when the bridge is created, and the configuration is removed * when the bridge is deleted. */ @Test public void testBridgeLifecycle(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); UUID tzId = createTunnelZone(1); final UUID bridgeId = UUID.randomUUID(); IPv4Addr vtepId = createVtep(1, tzId); hostZkManager.makeAlive(hostId); addTunnelZoneMember(tzId, hostId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(anyString, anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Clear flooding proxy. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); createBridge(bridgeId, 1); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.bridgeCreateVxLanPort(bridgeId, vtepId, VTEP_MGMT_PORT, VTEP_VNI, getVtepAddress(1), tzId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.bridgeDeleteVxLanPort(bridgeId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.bridgesDelete(bridgeId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 hosts and 1 bridge. The tunnel zone and VTEP * are created aftre the VXGW service has started. * * The tunnel zone state should always have the host set as the current * flooding proxy. However, the VTEP is configured with the flooding proxy * only when the bridge creates a VXLAN port on the VTEP. */ @Test public void testVtepLifecycle(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); UUID tzId = createTunnelZone(1); final UUID bridgeId = createBridge(1); hostZkManager.makeAlive(hostId); addTunnelZoneMember(tzId, hostId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Clear flooding proxy. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); IPv4Addr vtepId = createVtep(1, tzId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.bridgeCreateVxLanPort(bridgeId, vtepId, VTEP_MGMT_PORT, VTEP_VNI, getVtepAddress(1), tzId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.bridgeDeleteVxLanPort(bridgeId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.vtepDelete(vtepId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that there is a flooding proxy set in a scenario with * 1 tunnel zone, 1 VTEP, 1 hosts and 1 bridge. The tunnel zone and VTEP * are created aftre the VXGW service has started. * * The tunnel zone state should always have the host set as the current * flooding proxy. However, the VTEP is configured with the flooding proxy * only when the bridge is created, and the configuration is removed * when the bridge is deleted. */ @Test public void testTunnelZoneVtepLifecycle(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId = createHost(1); final UUID bridgeId = createBridge(1); hostZkManager.makeAlive(hostId); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Clear flooding proxy. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); UUID tzId = createTunnelZone(1); assertEquals(vxgwService.getFloodingProxy(tzId), null); addTunnelZoneMember(tzId, hostId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); IPv4Addr vtepId = createVtep(1, tzId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.bridgeCreateVxLanPort(bridgeId, vtepId, VTEP_MGMT_PORT, VTEP_VNI, getVtepAddress(1), tzId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.bridgeDeleteVxLanPort(bridgeId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.vtepDelete(vtepId); assertEquals(vxgwService.getFloodingProxy(tzId), hostId); midoClient.tunnelZonesDeleteMembership(tzId, hostId); assertEquals(vxgwService.getFloodingProxy(tzId), null); midoClient.tunnelZonesDelete(tzId); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks that the flooding proxy is updated correctly when * a bridge changes the tunnel zone, in a scenario with 2 tunnel zones, * 2 VTEPs, 2 host and 2 bridges. * * The flooding proxy is a per-tunnel-zone property, but a VTEP must * configure a flooding proxy for each logical switch. */ @Test public void testBridgeChangeVxLanPort(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId1 = createHost(1); UUID hostId2 = createHost(2); UUID tzId1 = createTunnelZone(1); UUID tzId2 = createTunnelZone(2); IPv4Addr vtepId1 = createVtep(1, tzId1); IPv4Addr vtepId2 = createVtep(2, tzId2); final UUID bridgeId = createBridge(1); hostZkManager.makeAlive(hostId1); hostZkManager.makeAlive(hostId2); addTunnelZoneMember(tzId1, hostId1); addTunnelZoneMember(tzId2, hostId2); new Expectations() { { vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB1 = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB1.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB2 = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB2.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB1.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB1.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB1.advertiseMacs(); times = 1; // On bridge updated (VXLAN port): assign bridge to tunnel zone 1 vB1.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // On bridge updated (VXLAN port): cleared bridge from tunnel zone vB1.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; vB2.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB2.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB2.advertiseMacs(); times = 1; // On bridge updated (VXLAN port): assign bridge to tunnel zone 2 vB2.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(2).getAddress()))); times = 1; // On bridge updated (VXLAN port): cleared bridge from tunnel zone vB2.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), null)); times = 1; vtepClient.disconnect((UUID) any, true); times = 2; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId1), hostId1); assertEquals(vxgwService.getFloodingProxy(tzId2), hostId2); midoClient.bridgeCreateVxLanPort(bridgeId, vtepId1, VTEP_MGMT_PORT, VTEP_VNI, getVtepAddress(1), tzId1); midoClient.bridgeDeleteVxLanPort(bridgeId); midoClient.bridgeCreateVxLanPort(bridgeId, vtepId2, VTEP_MGMT_PORT, VTEP_VNI, getVtepAddress(2), tzId2); midoClient.bridgeDeleteVxLanPort(bridgeId); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks the flooding proxy in a scenario with four hosts * than initially have different flooding proxy weights and change their * alive status. * * The test is conducted in a scenario with 1 tunnel zone, 1 VTEP and 1 * bridge. * * The flooding proxy should change to the alive host with the maximum * flooding proxy weight. */ @Test public void testMultipleHostsWithHostAlive(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId1 = createHost(1); UUID hostId2 = createHost(2); UUID hostId3 = createHost(3); UUID hostId4 = createHost(4); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); hostZkManager.makeAlive(hostId1); hostZkManager.makeAlive(hostId2); hostZkManager.makeAlive(hostId3); hostZkManager.makeAlive(hostId4); addTunnelZoneMember(tzId, hostId1); addTunnelZoneMember(tzId, hostId2); addTunnelZoneMember(tzId, hostId3); addTunnelZoneMember(tzId, hostId4); midoClient.hostsSetFloodingProxyWeight(hostId1, 10); midoClient.hostsSetFloodingProxyWeight(hostId2, 20); midoClient.hostsSetFloodingProxyWeight(hostId3, 30); midoClient.hostsSetFloodingProxyWeight(hostId4, 40); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 4. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(4).getAddress()))); times = 1; // Set flooding proxy to host 3. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(3).getAddress()))); times = 1; // Set flooding proxy to host 4. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(4).getAddress()))); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Set flooding proxy to host 3. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(3).getAddress()))); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), hostId4); hostZkManager.makeNotAlive(hostId4); assertEquals(vxgwService.getFloodingProxy(tzId), hostId3); hostZkManager.makeAlive(hostId4); assertEquals(vxgwService.getFloodingProxy(tzId), hostId4); hostZkManager.makeNotAlive(hostId2); assertEquals(vxgwService.getFloodingProxy(tzId), hostId4); hostZkManager.makeNotAlive(hostId3); assertEquals(vxgwService.getFloodingProxy(tzId), hostId4); hostZkManager.makeNotAlive(hostId4); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); hostZkManager.makeAlive(hostId3); assertEquals(vxgwService.getFloodingProxy(tzId), hostId3); vxgwService.stopAsync().awaitTerminated(); } /** * This test checks the flooding proxy in a scenario with four hosts * that initially have different flooding proxy weights and change the * tunnel zone membership. * * The test is conducted in a scenario with 1 tunnel zone, 1 VTEP and 1 * bridge. * * The flooding proxy should change to the alive host with the maximum * flooding proxy weight. */ @Test public void testMultipleHostsWithTunnelZoneMembership(@Mocked final VtepBroker vtepBroker) throws Exception { UUID hostId1 = createHost(1); UUID hostId2 = createHost(2); UUID hostId3 = createHost(3); UUID hostId4 = createHost(4); UUID tzId = createTunnelZone(1); IPv4Addr vtepId = createVtep(1, tzId); final UUID bridgeId = createBridge(1, vtepId, getVtepAddress(1), tzId); hostZkManager.makeAlive(hostId1); hostZkManager.makeAlive(hostId2); hostZkManager.makeAlive(hostId3); hostZkManager.makeAlive(hostId4); addTunnelZoneMember(tzId, hostId1); midoClient.hostsSetFloodingProxyWeight(hostId1, 10); midoClient.hostsSetFloodingProxyWeight(hostId2, 20); midoClient.hostsSetFloodingProxyWeight(hostId3, 30); midoClient.hostsSetFloodingProxyWeight(hostId4, 40); new Expectations() { { vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any); result = vtepClient; times = 1; VtepBroker vB = new VtepBroker(vtepClient); times = 1; vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any); result = emptySubscription; times = 1; vB.observableUpdates(); result = Observable.empty(); times = 1; vtepClient.getTunnelIp(); times = 1; vB.ensureLogicalSwitchExists(VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), anyInt); times = 1; vB.renewBindings((org.opendaylight.ovsdb.lib.notation.UUID) any, (Collection<VtepBinding>) any); times = 1; vB.advertiseMacs(); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; // Set flooding proxy to host 2. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(2).getAddress()))); times = 1; // Set flooding proxy to host 3. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(3).getAddress()))); times = 1; // Set flooding proxy to host 4. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(4).getAddress()))); times = 1; // Set flooding proxy to host 1. vB.apply(new MacLocation(VtepMAC.UNKNOWN_DST, null, VtepConstants.bridgeIdToLogicalSwitchName(bridgeId), IPv4Addr.fromBytes(getHostAddress(1).getAddress()))); times = 1; vtepClient.disconnect((UUID) any, true); times = 1; } }; vxgwService.startAsync().awaitRunning(); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); addTunnelZoneMember(tzId, hostId2); assertEquals(vxgwService.getFloodingProxy(tzId), hostId2); addTunnelZoneMember(tzId, hostId3); assertEquals(vxgwService.getFloodingProxy(tzId), hostId3); addTunnelZoneMember(tzId, hostId4); assertEquals(vxgwService.getFloodingProxy(tzId), hostId4); midoClient.tunnelZonesDeleteMembership(tzId, hostId3); assertEquals(vxgwService.getFloodingProxy(tzId), hostId4); midoClient.tunnelZonesDeleteMembership(tzId, hostId2); assertEquals(vxgwService.getFloodingProxy(tzId), hostId4); midoClient.tunnelZonesDeleteMembership(tzId, hostId4); assertEquals(vxgwService.getFloodingProxy(tzId), hostId1); vxgwService.stopAsync().awaitTerminated(); } public UUID createTunnelZone(int index) throws StateAccessException, SerializationException { // Create the tunnel zone. TunnelZone tzone = new TunnelZone(); tzone.setName("TunnelZone-" + index); tzone.setType(TunnelZone.Type.vxlan); return midoClient.tunnelZonesCreate(tzone); } public void addTunnelZoneMember(UUID zoneId, UUID hostId) throws StateAccessException, SerializationException { Host host = midoClient.hostsGet(hostId); TunnelZone.HostConfig hostConfig = new TunnelZone.HostConfig(hostId); hostConfig.setIp(IPv4Addr.apply(host.getAddresses()[0].getAddress())); midoClient.tunnelZonesAddMembership(zoneId, hostConfig); } public IPv4Addr createVtep(int index, UUID tzoneId) throws StateAccessException, SerializationException { // Create the VTEP. VTEP vtep = new VTEP(); vtep.setId(getVtepAddress(index)); vtep.setMgmtPort(VTEP_MGMT_PORT); vtep.setTunnelZone(tzoneId); midoClient.vtepCreate(vtep); return vtep.getId(); } public UUID createHost(int index) throws StateAccessException, SerializationException, UnknownHostException { Host host = new Host(); host.setName("Host-" + index); host.setAddresses(new InetAddress[] { getHostAddress(index) }); return midoClient.hostsCreate(UUID.randomUUID(), host); } public UUID createBridge(int index) throws SerializationException, StateAccessException { Bridge bridge = new Bridge(); bridge.setName("Bridge-" + index); return midoClient.bridgesCreate(bridge); } public UUID createBridge(UUID id, int index) throws SerializationException, StateAccessException { Bridge bridge = new Bridge(id); bridge.setName("Bridge-" + index); return midoClient.bridgesCreate(bridge); } public UUID createBridge(int index, IPv4Addr mgmtIp, IPv4Addr tunnelIp, UUID tzId) throws StateAccessException, SerializationException { UUID bridgeId = createBridge(index); midoClient.bridgeCreateVxLanPort(bridgeId, mgmtIp, VTEP_MGMT_PORT, VTEP_VNI, tunnelIp, tzId); return bridgeId; } public static IPv4Addr getVtepAddress(int value) { return IPv4Addr.apply(new byte[] { VTEP_MGMT_IP[0], VTEP_MGMT_IP[1], (byte) ((value >> 8) & 0xFF), (byte) (value & 0xFF) }); } public static InetAddress getHostAddress(int value) throws UnknownHostException { return InetAddress.getByAddress( new byte[] { HOST_IP[0], HOST_IP[1], (byte) ((value >> 8) & 0xFF), (byte) (value & 0xFF) }); } }