Brian Stanke
Committed by Gerrit Code Review

ONOS-4075 - Distributed virtual network store implementation,

and virtual network manager Junit tests.

Change-Id: Ic1f82822c894e3c394aa95df1e76ae59fe218120
......@@ -64,7 +64,7 @@ public class DistributedSetTest {
public void basicTests() {
set1.add("item1");
assertEquals("The set name should match.", SETNAME, set1.name());
assertEquals("The set name should match.", DistributedPrimitive.Type.SET, set1.primitiveType());
assertEquals("The set primitive type should match.", DistributedPrimitive.Type.SET, set1.primitiveType());
set1.add("item2");
set1.add("item3");
......
......@@ -27,7 +27,7 @@ import static com.google.common.base.MoreObjects.*;
/**
* Default representation of a virtual device.
*/
public class DefaultVirtualDevice extends DefaultDevice implements VirtualDevice {
public final class DefaultVirtualDevice extends DefaultDevice implements VirtualDevice {
private static final String VIRTUAL = "virtual";
private static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
......@@ -53,7 +53,7 @@ public class DefaultVirtualDevice extends DefaultDevice implements VirtualDevice
@Override
public int hashCode() {
return 31 * super.hashCode() + networkId.hashCode();
return Objects.hash(networkId);
}
@Override
......
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.incubator.net.virtual;
import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultLink;
import org.onosproject.net.provider.ProviderId;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Default representation of a virtual link.
*/
public final class DefaultVirtualLink extends DefaultLink implements VirtualLink {
private static final String VIRTUAL = "virtual";
private static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
private final NetworkId networkId;
private final TunnelId tunnelId;
/**
* Constructor for a default virtual link.
*
* @param networkId network identifier
* @param src source connection point
* @param dst destination connection point
* @param tunnelId tunnel identifier
*/
public DefaultVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId) {
super(PID, src, dst, Type.VIRTUAL, DefaultAnnotations.builder().build());
this.networkId = networkId;
this.tunnelId = tunnelId;
}
@Override
public NetworkId networkId() {
return networkId;
}
/**
* Returns the tunnel identifier.
*
* @return tunnel identifier.
*/
public TunnelId tunnelId() {
return tunnelId;
}
@Override
public int hashCode() {
return Objects.hash(networkId, tunnelId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DefaultVirtualLink) {
DefaultVirtualLink that = (DefaultVirtualLink) obj;
return super.equals(that) &&
Objects.equals(this.networkId, that.networkId) &&
Objects.equals(this.tunnelId, that.tunnelId);
}
return false;
}
@Override
public String toString() {
return toStringHelper(this).add("networkId", networkId).add("tunnelId", tunnelId).toString();
}
}
......@@ -22,7 +22,7 @@ import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Default implementation of the virtual network descriptor.
*/
public class DefaultVirtualNetwork implements VirtualNetwork {
public final class DefaultVirtualNetwork implements VirtualNetwork {
private final NetworkId id;
private final TenantId tenantId;
......
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.incubator.net.virtual;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultPort;
import org.onosproject.net.Device;
import org.onosproject.net.Element;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Default representation of a virtual port.
*/
public final class DefaultVirtualPort extends DefaultPort implements VirtualPort {
private final NetworkId networkId;
private final Port realizedBy;
public DefaultVirtualPort(NetworkId networkId, Device device, PortNumber portNumber, Port realizedBy) {
super((Element) device, portNumber, false, DefaultAnnotations.builder().build());
this.networkId = networkId;
this.realizedBy = realizedBy;
}
public NetworkId networkId() {
return networkId;
}
@Override
public Port realizedBy() {
return realizedBy;
}
@Override
public int hashCode() {
return Objects.hash(networkId, realizedBy);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DefaultVirtualPort) {
DefaultVirtualPort that = (DefaultVirtualPort) obj;
return super.equals(that) &&
Objects.equals(this.networkId, that.networkId) &&
Objects.equals(this.realizedBy, that.realizedBy);
}
return false;
}
@Override
public String toString() {
return toStringHelper(this).add("networkId", networkId).add("realizedBy", realizedBy).toString();
}
}
......@@ -27,6 +27,11 @@ import java.util.Set;
public interface VirtualNetworkService {
/**
* The topic used for obtaining globally unique ids.
*/
String VIRTUAL_NETWORK_TOPIC = "virtual-network-ids";
/**
* Returns a collection of all virtual networks created on behalf of the
* specified tenant.
*
......
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.incubator.net.virtual;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import org.onosproject.net.DeviceId;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
/**
* Test of the default virtual device model entity.
*/
public class DefaultVirtualDeviceTest {
final String deviceIdValue1 = "DEVICE_ID1";
final String deviceIdValue2 = "DEVICE_ID2";
/**
* Checks that the DefaultVirtualDevice class is immutable.
*/
@Test
public void testImmutability() {
assertThatClassIsImmutable(DefaultVirtualDevice.class);
}
@Test
public void testEquality() {
DefaultVirtualDevice device1 =
new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue1));
DefaultVirtualDevice device2 =
new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue1));
DefaultVirtualDevice device3 =
new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue2));
DefaultVirtualDevice device4 =
new DefaultVirtualDevice(NetworkId.networkId(1), DeviceId.deviceId(deviceIdValue1));
new EqualsTester().addEqualityGroup(device1, device2).addEqualityGroup(device3)
.addEqualityGroup(device4).testEquals();
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.incubator.net.virtual;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
/**
* Test of the default virtual link model entity.
*/
public class DefaultVirtualLinkTest {
final String deviceIdValue1 = "DEVICE_ID1";
final String deviceIdValue2 = "DEVICE_ID2";
/**
* Checks that the DefaultVirtualLink class is immutable.
*/
@Test
public void testImmutability() {
assertThatClassIsImmutable(DefaultVirtualLink.class);
}
@Test
public void testEquality() {
DefaultVirtualDevice device1 =
new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue1));
DefaultVirtualDevice device2 =
new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue2));
ConnectPoint src = new ConnectPoint(device1.id(), PortNumber.portNumber(1));
ConnectPoint dst = new ConnectPoint(device2.id(), PortNumber.portNumber(2));
DefaultVirtualLink link1 = new DefaultVirtualLink(NetworkId.networkId(0), src, dst, TunnelId.valueOf(0));
DefaultVirtualLink link2 = new DefaultVirtualLink(NetworkId.networkId(0), src, dst, TunnelId.valueOf(0));
DefaultVirtualLink link3 = new DefaultVirtualLink(NetworkId.networkId(0), src, dst, TunnelId.valueOf(1));
DefaultVirtualLink link4 = new DefaultVirtualLink(NetworkId.networkId(1), src, dst, TunnelId.valueOf(0));
new EqualsTester().addEqualityGroup(link1, link2).addEqualityGroup(link3)
.addEqualityGroup(link4).testEquals();
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.incubator.net.virtual;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
/**
* Test of the default virtual network model entity.
*/
public class DefaultVirtualNetworkTest {
final String tenantIdValue1 = "TENANT_ID1";
final String tenantIdValue2 = "TENANT_ID2";
/**
* Checks that the DefaultVirtualNetwork class is immutable.
*/
@Test
public void testImmutability() {
assertThatClassIsImmutable(DefaultVirtualNetwork.class);
}
@Test
public void testEquality() {
DefaultVirtualNetwork network1 =
new DefaultVirtualNetwork(NetworkId.networkId(0), TenantId.tenantId(tenantIdValue1));
DefaultVirtualNetwork network2 =
new DefaultVirtualNetwork(NetworkId.networkId(0), TenantId.tenantId(tenantIdValue1));
DefaultVirtualNetwork network3 =
new DefaultVirtualNetwork(NetworkId.networkId(0), TenantId.tenantId(tenantIdValue2));
DefaultVirtualNetwork network4 =
new DefaultVirtualNetwork(NetworkId.networkId(1), TenantId.tenantId(tenantIdValue2));
new EqualsTester().addEqualityGroup(network1, network2).addEqualityGroup(network3)
.addEqualityGroup(network4).testEquals();
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.incubator.net.virtual;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import org.onosproject.net.DefaultPort;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
/**
* Test of the default virtual port model entity.
*/
public class DefaultVirtualPortTest {
final String deviceIdValue1 = "DEVICE_ID1";
final String deviceIdValue2 = "DEVICE_ID2";
/**
* Checks that the DefaultVirtualPort class is immutable.
*/
@Test
public void testImmutability() {
assertThatClassIsImmutable(DefaultVirtualPort.class);
}
@Test
public void testEquality() {
DefaultVirtualDevice device1 =
new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue1));
DefaultVirtualDevice device2 =
new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue2));
Port portA = new DefaultPort(device1, PortNumber.portNumber(1), true);
Port portB = new DefaultPort(device1, PortNumber.portNumber(2), true);
Port portC = new DefaultPort(device2, PortNumber.portNumber(2), true);
DefaultVirtualPort port1 =
new DefaultVirtualPort(NetworkId.networkId(0), device1, PortNumber.portNumber(1), portA);
DefaultVirtualPort port2 =
new DefaultVirtualPort(NetworkId.networkId(0), device1, PortNumber.portNumber(1), portA);
DefaultVirtualPort port3 =
new DefaultVirtualPort(NetworkId.networkId(0), device1, PortNumber.portNumber(2), portB);
DefaultVirtualPort port4 =
new DefaultVirtualPort(NetworkId.networkId(1), device2, PortNumber.portNumber(2), portC);
new EqualsTester().addEqualityGroup(port1, port2).addEqualityGroup(port3)
.addEqualityGroup(port4).testEquals();
}
}
/*
* Copyright 2015 Open Networking Laboratory
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -70,19 +70,23 @@ public class VirtualNetworkManager
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected VirtualNetworkStore store;
private VirtualNetworkStoreDelegate delegate = new InternalStoreDelegate();
private VirtualNetworkStoreDelegate delegate = this::post;
// TODO: figure out how to coordinate "implementation" of a virtual network in a cluster
@Activate
protected void activate() {
store.setDelegate(delegate);
eventDispatcher.addSink(VirtualNetworkEvent.class, listenerRegistry);
log.info("Started");
}
@Deactivate
protected void deactivate() {
store.unsetDelegate(delegate);
eventDispatcher.removeSink(VirtualNetworkEvent.class);
log.info("Stopped");
}
......@@ -211,13 +215,4 @@ public class VirtualNetworkManager
}
}
// Auxiliary store delegate to receive notification about changes in
// the virtual network configuration store state - by the store itself.
private class InternalStoreDelegate implements VirtualNetworkStoreDelegate {
@Override
public void notify(VirtualNetworkEvent event) {
post(event);
}
}
}
......
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.onosproject.incubator.net.virtual.impl;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestTools;
import org.onlab.junit.TestUtils;
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.core.CoreService;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.core.IdGenerator;
import org.onosproject.event.Event;
import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultPort;
import org.onosproject.net.DeviceId;
import org.onosproject.net.NetTestTools;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.store.service.TestStorageService;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.*;
/**
* Junit tests for VirtualNetworkManager.
*/
public class VirtualNetworkManagerTest {
final String tenantIdValue1 = "TENANT_ID1";
final String tenantIdValue2 = "TENANT_ID2";
final String deviceIdValue1 = "DEVICE_ID1";
final String deviceIdValue2 = "DEVICE_ID2";
private VirtualNetworkManager manager;
private VirtualNetworkService virtualNetworkManagerService;
private DistributedVirtualNetworkStore virtualNetworkManagerStore;
private CoreService coreService;
protected TestListener listener = new TestListener();
@Before
public void setUp() throws Exception {
virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
coreService = new TestCoreService();
virtualNetworkManagerStore.setCoreService(coreService);
TestUtils.setField(coreService, "coreService", new TestCoreService());
TestUtils.setField(virtualNetworkManagerStore, "storageService", new TestStorageService());
virtualNetworkManagerStore.activate();
manager = new VirtualNetworkManager();
manager.store = virtualNetworkManagerStore;
manager.addListener(listener);
NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
manager.activate();
virtualNetworkManagerService = manager;
}
@After
public void tearDown() {
virtualNetworkManagerStore.deactivate();
manager.removeListener(listener);
manager.deactivate();
NetTestTools.injectEventDispatcher(manager, null);
}
/**
* Tests registering a null tenant id.
*/
@Test(expected = NullPointerException.class)
public void testRegisterNullTenantId() {
manager.registerTenantId(null);
}
/**
* Tests registering/unregistering a tenant id.
*/
@Test
public void testRegisterUnregisterTenantId() {
manager.unregisterTenantId(TenantId.tenantId(tenantIdValue1));
manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
manager.registerTenantId(TenantId.tenantId(tenantIdValue2));
Collection<TenantId> tenantIdCollection = manager.getTenantIds();
assertEquals("The tenantId set size did not match.", 2, tenantIdCollection.size());
manager.unregisterTenantId(TenantId.tenantId(tenantIdValue1));
manager.unregisterTenantId(TenantId.tenantId(tenantIdValue2));
tenantIdCollection = manager.getTenantIds();
assertTrue("The tenantId set should be empty.", tenantIdCollection.isEmpty());
// Validate that the events were all received in the correct order.
validateEvents(VirtualNetworkEvent.Type.TENANT_UNREGISTERED, VirtualNetworkEvent.Type.TENANT_REGISTERED,
VirtualNetworkEvent.Type.TENANT_REGISTERED, VirtualNetworkEvent.Type.TENANT_UNREGISTERED,
VirtualNetworkEvent.Type.TENANT_UNREGISTERED);
}
/**
* Tests adding a null virtual network.
*/
@Test(expected = NullPointerException.class)
public void testCreateNullVirtualNetwork() {
manager.createVirtualNetwork(null);
}
/**
* Tests add and remove of virtual networks.
*/
@Test
public void testAddRemoveVirtualNetwork() {
manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
Set<VirtualNetwork> virtualNetworks = manager.getVirtualNetworks(TenantId.tenantId(tenantIdValue1));
assertNotNull("The virtual network set should not be null", virtualNetworks);
assertEquals("The virtual network set size did not match.", 2, virtualNetworks.size());
for (VirtualNetwork virtualNetwork : virtualNetworks) {
manager.removeVirtualNetwork(virtualNetwork.id());
// attempt to remove the same virtual network again.
manager.removeVirtualNetwork(virtualNetwork.id());
}
virtualNetworks = manager.getVirtualNetworks(TenantId.tenantId(tenantIdValue1));
assertTrue("The virtual network set should be empty.", virtualNetworks.isEmpty());
// Validate that the events were all received in the correct order.
validateEvents(VirtualNetworkEvent.Type.TENANT_REGISTERED, VirtualNetworkEvent.Type.NETWORK_ADDED,
VirtualNetworkEvent.Type.NETWORK_ADDED, VirtualNetworkEvent.Type.NETWORK_REMOVED,
VirtualNetworkEvent.Type.NETWORK_REMOVED);
}
/**
* Tests adding a null virtual device.
*/
@Test(expected = NullPointerException.class)
public void testCreateNullVirtualDevice() {
manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
manager.createVirtualDevice(virtualNetwork.id(), null);
}
/**
* Tests adding a virtual device where no virtual network exists.
*/
@Test(expected = IllegalStateException.class)
public void testCreateVirtualDeviceWithNoNetwork() {
manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
VirtualNetwork virtualNetwork = new DefaultVirtualNetwork(NetworkId.NONE, TenantId.tenantId(tenantIdValue1));
manager.createVirtualDevice(virtualNetwork.id(), DeviceId.deviceId(deviceIdValue1));
}
/**
* Tests add and remove of virtual devices.
*/
@Test
public void testAddRemoveVirtualDevice() {
manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
VirtualNetwork virtualNetwork1 = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
VirtualNetwork virtualNetwork2 = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue1));
manager.createVirtualDevice(virtualNetwork2.id(), DeviceId.deviceId(deviceIdValue2));
Set<VirtualDevice> virtualDevices1 = manager.getVirtualDevices(virtualNetwork1.id());
assertNotNull("The virtual device set should not be null", virtualDevices1);
assertEquals("The virtual device set size did not match.", 1, virtualDevices1.size());
Set<VirtualDevice> virtualDevices2 = manager.getVirtualDevices(virtualNetwork2.id());
assertNotNull("The virtual device set should not be null", virtualDevices2);
assertEquals("The virtual device set size did not match.", 1, virtualDevices2.size());
for (VirtualDevice virtualDevice : virtualDevices1) {
manager.removeVirtualDevice(virtualNetwork1.id(), virtualDevice.id());
// attempt to remove the same virtual device again.
manager.removeVirtualDevice(virtualNetwork1.id(), virtualDevice.id());
}
virtualDevices1 = manager.getVirtualDevices(virtualNetwork1.id());
assertTrue("The virtual device set should be empty.", virtualDevices1.isEmpty());
// Validate that the events were all received in the correct order.
validateEvents(VirtualNetworkEvent.Type.TENANT_REGISTERED, VirtualNetworkEvent.Type.NETWORK_ADDED,
VirtualNetworkEvent.Type.NETWORK_ADDED);
}
/**
* Tests add and remove of virtual links.
*/
@Test
public void testAddRemoveVirtualLink() {
manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
VirtualNetwork virtualNetwork1 = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
VirtualDevice srcVirtualDevice =
manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue1));
VirtualDevice dstVirtualDevice =
manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue2));
ConnectPoint src = new ConnectPoint(srcVirtualDevice.id(), PortNumber.portNumber(1));
ConnectPoint dst = new ConnectPoint(dstVirtualDevice.id(), PortNumber.portNumber(2));
manager.createVirtualLink(virtualNetwork1.id(), src, dst, TunnelId.valueOf(0));
manager.createVirtualLink(virtualNetwork1.id(), dst, src, TunnelId.valueOf(1));
Set<VirtualLink> virtualLinks = manager.getVirtualLinks(virtualNetwork1.id());
assertNotNull("The virtual link set should not be null", virtualLinks);
assertEquals("The virtual link set size did not match.", 2, virtualLinks.size());
for (VirtualLink virtualLink : virtualLinks) {
manager.removeVirtualLink(virtualLink.networkId(), virtualLink.src(), virtualLink.dst());
// attempt to remove the same virtual link again.
manager.removeVirtualLink(virtualLink.networkId(), virtualLink.src(), virtualLink.dst());
}
virtualLinks = manager.getVirtualLinks(virtualNetwork1.id());
assertTrue("The virtual link set should be empty.", virtualLinks.isEmpty());
}
/**
* Tests add and remove of virtual ports.
*/
@Test
public void testAddRemoveVirtualPort() {
manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
VirtualNetwork virtualNetwork1 = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
VirtualDevice srcVirtualDevice =
manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue1));
VirtualDevice dstVirtualDevice =
manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue2));
Port port = new DefaultPort(srcVirtualDevice, PortNumber.portNumber(1), true);
manager.createVirtualPort(virtualNetwork1.id(), srcVirtualDevice.id(), PortNumber.portNumber(1), port);
manager.createVirtualPort(virtualNetwork1.id(), dstVirtualDevice.id(), PortNumber.portNumber(1), port);
Set<VirtualPort> virtualPorts = manager.getVirtualPorts(virtualNetwork1.id(), srcVirtualDevice.id());
assertNotNull("The virtual port set should not be null", virtualPorts);
assertEquals("The virtual port set size did not match.", 2, virtualPorts.size());
for (VirtualPort virtualPort : virtualPorts) {
manager.removeVirtualPort(virtualNetwork1.id(),
(DeviceId) virtualPort.element().id(), virtualPort.number());
// attempt to remove the same virtual port again.
manager.removeVirtualPort(virtualNetwork1.id(),
(DeviceId) virtualPort.element().id(), virtualPort.number());
}
virtualPorts = manager.getVirtualPorts(virtualNetwork1.id(), srcVirtualDevice.id());
assertTrue("The virtual port set should be empty.", virtualPorts.isEmpty());
}
/**
* Method to validate that the actual versus expected virtual network events were
* received correctly.
*
* @param types expected virtual network events.
*/
private void validateEvents(Enum... types) {
TestTools.assertAfter(100, () -> {
int i = 0;
assertEquals("wrong events received", types.length, listener.events.size());
for (Event event : listener.events) {
assertEquals("incorrect event type", types[i], event.type());
i++;
}
listener.events.clear();
});
}
/**
* Test listener class to receive virtual network events.
*/
private static class TestListener implements VirtualNetworkListener {
protected List<VirtualNetworkEvent> events = Lists.newArrayList();
@Override
public void event(VirtualNetworkEvent event) {
events.add(event);
}
}
private class TestCoreService extends CoreServiceAdapter {
@Override
public IdGenerator getIdGenerator(String topic) {
return new IdGenerator() {
private AtomicLong counter = new AtomicLong(0);
@Override
public long getNewId() {
return counter.getAndIncrement();
}
};
}
}
}
/*
* Copyright 2015 Open Networking Laboratory
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -15,35 +15,59 @@
*/
package org.onosproject.incubator.store.virtual.impl;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.CoreService;
import org.onosproject.core.IdGenerator;
import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
import org.onosproject.incubator.net.virtual.DefaultVirtualPort;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.DistributedSet;
import org.onosproject.store.service.MapEvent;
import org.onosproject.store.service.MapEventListener;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.SetEvent;
import org.onosproject.store.service.SetEventListener;
import org.onosproject.store.service.StorageService;
import org.slf4j.Logger;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Implementation of the network store.
* Implementation of the virtual network store.
*/
@Component(immediate = true)
@Service
......@@ -53,95 +77,404 @@ public class DistributedVirtualNetworkStore
private final Logger log = getLogger(getClass());
// TODO: track tenants by ID
// TODO: track networks by ID and by tenants
// TODO: track devices by network ID and device ID
// TODO: track devices by network ID
// TODO: setup block allocator for network IDs
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
// TODO: notify delegate
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
private IdGenerator idGenerator;
// Track tenants by ID
private DistributedSet<TenantId> tenantIdSet;
// Listener for tenant events
private final SetEventListener<TenantId> setListener = new InternalSetListener();
// Track virtual networks by network Id
private ConsistentMap<NetworkId, VirtualNetwork> networkIdVirtualNetworkConsistentMap;
private Map<NetworkId, VirtualNetwork> networkIdVirtualNetworkMap;
// Listener for virtual network events
private final MapEventListener<NetworkId, VirtualNetwork> virtualMapListener = new InternalMapListener();
// Track virtual network IDs by tenant Id
private ConsistentMap<TenantId, Set<NetworkId>> tenantIdNetworkIdSetConsistentMap;
private Map<TenantId, Set<NetworkId>> tenantIdNetworkIdSetMap;
// Track virtual devices by device Id
private ConsistentMap<DeviceId, VirtualDevice> deviceIdVirtualDeviceConsistentMap;
private Map<DeviceId, VirtualDevice> deviceIdVirtualDeviceMap;
// Track device IDs by network Id
private ConsistentMap<NetworkId, Set<DeviceId>> networkIdDeviceIdSetConsistentMap;
private Map<NetworkId, Set<DeviceId>> networkIdDeviceIdSetMap;
// Track virtual links by network Id
private ConsistentMap<NetworkId, Set<VirtualLink>> networkIdVirtualLinkSetConsistentMap;
private Map<NetworkId, Set<VirtualLink>> networkIdVirtualLinkSetMap;
// Track virtual ports by network Id
private ConsistentMap<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetConsistentMap;
private Map<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetMap;
private static final Serializer SERIALIZER = Serializer
.using(new KryoNamespace.Builder().register(KryoNamespaces.API)
.register(TenantId.class)
.register(NetworkId.class).register(DeviceId.class)
.register(VirtualNetwork.class)
.register(VirtualDevice.class)
.register(VirtualLink.class)
.register(VirtualPort.class)
.register(DeviceId.class)
.register(Device.class)
.nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID).build());
/**
* Distributed network store service activate method.
*/
@Activate
public void activate() {
idGenerator = coreService.getIdGenerator(VirtualNetworkService.VIRTUAL_NETWORK_TOPIC);
tenantIdSet = storageService.<TenantId>setBuilder()
.withSerializer(SERIALIZER)
.withName("onos-tenantId")
.withRelaxedReadConsistency()
.build()
.asDistributedSet();
tenantIdSet.addListener(setListener);
networkIdVirtualNetworkConsistentMap = storageService.<NetworkId, VirtualNetwork>consistentMapBuilder()
.withSerializer(SERIALIZER)
.withName("onos-networkId-virtualnetwork")
.withRelaxedReadConsistency()
.build();
networkIdVirtualNetworkConsistentMap.addListener(virtualMapListener);
networkIdVirtualNetworkMap = networkIdVirtualNetworkConsistentMap.asJavaMap();
tenantIdNetworkIdSetConsistentMap = storageService.<TenantId, Set<NetworkId>>consistentMapBuilder()
.withSerializer(SERIALIZER)
.withName("onos-tenantId-networkIds")
.withRelaxedReadConsistency()
.build();
tenantIdNetworkIdSetMap = tenantIdNetworkIdSetConsistentMap.asJavaMap();
deviceIdVirtualDeviceConsistentMap = storageService.<DeviceId, VirtualDevice>consistentMapBuilder()
.withSerializer(SERIALIZER)
.withName("onos-deviceId-virtualdevice")
.withRelaxedReadConsistency()
.build();
deviceIdVirtualDeviceMap = deviceIdVirtualDeviceConsistentMap.asJavaMap();
networkIdDeviceIdSetConsistentMap = storageService.<NetworkId, Set<DeviceId>>consistentMapBuilder()
.withSerializer(SERIALIZER)
.withName("onos-networkId-deviceIds")
.withRelaxedReadConsistency()
.build();
networkIdDeviceIdSetMap = networkIdDeviceIdSetConsistentMap.asJavaMap();
networkIdVirtualLinkSetConsistentMap = storageService.<NetworkId, Set<VirtualLink>>consistentMapBuilder()
.withSerializer(SERIALIZER)
.withName("onos-networkId-virtuallinks")
.withRelaxedReadConsistency()
.build();
networkIdVirtualLinkSetMap = networkIdVirtualLinkSetConsistentMap.asJavaMap();
networkIdVirtualPortSetConsistentMap = storageService.<NetworkId, Set<VirtualPort>>consistentMapBuilder()
.withSerializer(SERIALIZER)
.withName("onos-networkId-virtualportss")
.withRelaxedReadConsistency()
.build();
networkIdVirtualPortSetMap = networkIdVirtualPortSetConsistentMap.asJavaMap();
log.info("Started");
}
/**
* Distributed network store service deactivate method.
*/
@Deactivate
public void deactivate() {
tenantIdSet.removeListener(setListener);
networkIdVirtualNetworkConsistentMap.removeListener(virtualMapListener);
log.info("Stopped");
}
/**
* This method is used for Junit tests to set the CoreService instance, which
* is required to set the IdGenerator instance.
*
* @param coreService core service instance
*/
public void setCoreService(CoreService coreService) {
this.coreService = coreService;
}
@Override
public void addTenantId(TenantId tenantId) {
tenantIdSet.add(tenantId);
}
@Override
public void removeTenantId(TenantId tenantId) {
tenantIdSet.remove(tenantId);
}
@Override
public Set<TenantId> getTenantIds() {
return null;
return ImmutableSet.copyOf(tenantIdSet);
}
@Override
public VirtualNetwork addNetwork(TenantId tenantId) {
return new DefaultVirtualNetwork(genNetworkId(), tenantId);
checkState(tenantIdSet.contains(tenantId), "The tenant has not been registered. " + tenantId.id());
VirtualNetwork virtualNetwork = new DefaultVirtualNetwork(genNetworkId(), tenantId);
//TODO update both maps in one transaction.
networkIdVirtualNetworkMap.put(virtualNetwork.id(), virtualNetwork);
Set<NetworkId> virtualNetworkSet = tenantIdNetworkIdSetMap.get(tenantId);
if (virtualNetworkSet == null) {
virtualNetworkSet = new HashSet<>();
}
virtualNetworkSet.add(virtualNetwork.id());
tenantIdNetworkIdSetMap.put(tenantId, virtualNetworkSet);
return virtualNetwork;
}
/**
* Returns a new network identifier from a virtual network block of identifiers.
*
* @return NetworkId network identifier
*/
private NetworkId genNetworkId() {
return NetworkId.networkId(0); // TODO: use a block allocator
return NetworkId.networkId(idGenerator.getNewId());
}
@Override
public void removeNetwork(NetworkId networkId) {
// Make sure that the virtual network exists before attempting to remove it.
if (networkExists(networkId)) {
VirtualNetwork virtualNetwork = networkIdVirtualNetworkMap.get(networkId);
if (virtualNetwork == null) {
return;
}
//TODO update both maps in one transaction.
TenantId tenantId = virtualNetwork.tenantId();
networkIdVirtualNetworkMap.compute(networkId, (id, existingVirtualNetwork) -> null);
Set<NetworkId> virtualNetworkSet = tenantIdNetworkIdSetMap.get(tenantId);
tenantIdNetworkIdSetMap.compute(virtualNetwork.tenantId(), (id, existingNetworkIds) -> {
if (existingNetworkIds == null || existingNetworkIds.isEmpty()) {
return ImmutableSet.of();
} else {
return ImmutableSet.<NetworkId>builder()
.addAll(Sets.difference(existingNetworkIds,
ImmutableSet.copyOf(virtualNetworkSet)))
.build();
}
});
}
}
/**
* Returns if the network identifier exists.
*
* @param networkId network identifier
* @return true if the network identifier exists, false otherwise.
*/
private boolean networkExists(NetworkId networkId) {
return (networkIdVirtualNetworkMap.containsKey(networkId));
}
@Override
public VirtualDevice addDevice(NetworkId networkId, DeviceId deviceId) {
return new DefaultVirtualDevice(networkId, deviceId);
checkState(networkExists(networkId), "The network has not been added.");
Set<DeviceId> deviceIdSet = networkIdDeviceIdSetMap.get(networkId);
if (deviceIdSet == null) {
deviceIdSet = new HashSet<>();
}
VirtualDevice virtualDevice = new DefaultVirtualDevice(networkId, deviceId);
//TODO update both maps in one transaction.
deviceIdVirtualDeviceMap.put(deviceId, virtualDevice);
deviceIdSet.add(deviceId);
networkIdDeviceIdSetMap.put(networkId, deviceIdSet);
return virtualDevice;
}
@Override
public void removeDevice(NetworkId networkId, DeviceId deviceId) {
checkState(networkExists(networkId), "The network has not been added.");
//TODO update both maps in one transaction.
Set<DeviceId> deviceIdSet = networkIdDeviceIdSetMap.get(networkId);
if (deviceIdSet != null) {
networkIdDeviceIdSetMap.compute(networkId, (id, existingDeviceIds) -> {
if (existingDeviceIds == null || existingDeviceIds.isEmpty()) {
return ImmutableSet.of();
} else {
return ImmutableSet.<DeviceId>builder()
.addAll(Sets.difference(existingDeviceIds,
ImmutableSet.copyOf(deviceIdSet)))
.build();
}
});
deviceIdVirtualDeviceMap.compute(deviceId, (id, existingVirtualDevice) -> null);
log.info("The deviceIdVirtualDeviceMap size is: " + getDevices(networkId));
}
}
@Override
public VirtualLink addLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId realizedBy) {
return null;
checkState(networkExists(networkId), "The network has not been added.");
Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(networkId);
if (virtualLinkSet == null) {
virtualLinkSet = new HashSet<>();
}
VirtualLink virtualLink = new DefaultVirtualLink(networkId, src, dst, realizedBy);
virtualLinkSet.add(virtualLink);
networkIdVirtualLinkSetMap.put(networkId, virtualLinkSet);
return virtualLink;
}
@Override
public void removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
checkState(networkExists(networkId), "The network has not been added.");
Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(networkId);
if (virtualLinkSet != null) {
networkIdVirtualLinkSetMap.compute(networkId, (id, existingVirtualLinks) -> {
if (existingVirtualLinks == null || existingVirtualLinks.isEmpty()) {
return ImmutableSet.of();
} else {
return ImmutableSet.<VirtualLink>builder()
.addAll(Sets.difference(existingVirtualLinks,
ImmutableSet.copyOf(virtualLinkSet)))
.build();
}
});
}
}
@Override
public VirtualPort addPort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber, Port realizedBy) {
return null;
checkState(networkExists(networkId), "The network has not been added.");
Set<VirtualPort> virtualPortSet = networkIdVirtualPortSetMap.get(networkId);
if (virtualPortSet == null) {
virtualPortSet = new HashSet<>();
}
Device device = deviceIdVirtualDeviceMap.get(deviceId);
checkNotNull(device, "The device has not been created for deviceId: " + deviceId);
VirtualPort virtualPort = new DefaultVirtualPort(networkId, device, portNumber, realizedBy);
virtualPortSet.add(virtualPort);
networkIdVirtualPortSetMap.put(networkId, virtualPortSet);
return virtualPort;
}
@Override
public void removePort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
checkState(networkExists(networkId), "The network has not been added.");
Set<VirtualPort> virtualPortSet = networkIdVirtualPortSetMap.get(networkId);
if (virtualPortSet != null) {
networkIdVirtualPortSetMap.compute(networkId, (id, existingVirtualPorts) -> {
if (existingVirtualPorts == null || existingVirtualPorts.isEmpty()) {
return ImmutableSet.of();
} else {
return ImmutableSet.<VirtualPort>builder()
.addAll(Sets.difference(existingVirtualPorts,
ImmutableSet.copyOf(virtualPortSet)))
.build();
}
});
}
}
@Override
public Set<VirtualNetwork> getNetworks(TenantId tenantId) {
return null;
Set<NetworkId> networkIdSet = tenantIdNetworkIdSetMap.get(tenantId);
Set<VirtualNetwork> virtualNetworkSet = new HashSet<>();
if (networkIdSet != null) {
networkIdSet.forEach(networkId -> virtualNetworkSet.add(networkIdVirtualNetworkMap.get(networkId)));
}
return ImmutableSet.copyOf(virtualNetworkSet);
}
@Override
public Set<VirtualDevice> getDevices(NetworkId networkId) {
return null;
checkState(networkExists(networkId), "The network has not been added.");
Set<DeviceId> deviceIdSet = networkIdDeviceIdSetMap.get(networkId);
Set<VirtualDevice> virtualDeviceSet = new HashSet<>();
if (deviceIdSet != null) {
deviceIdSet.forEach(deviceId -> virtualDeviceSet.add(deviceIdVirtualDeviceMap.get(deviceId)));
}
return ImmutableSet.copyOf(virtualDeviceSet);
}
@Override
public Set<VirtualLink> getLinks(NetworkId networkId) {
return null;
checkState(networkExists(networkId), "The network has not been added.");
Set<VirtualLink> virtualLinkSet = new HashSet<>();
virtualLinkSet.addAll(networkIdVirtualLinkSetMap.get(networkId));
return ImmutableSet.copyOf(virtualLinkSet);
}
@Override
public Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId) {
return null;
checkState(networkExists(networkId), "The network has not been added.");
Set<VirtualPort> virtualPortSet = new HashSet<>();
virtualPortSet.addAll(networkIdVirtualPortSetMap.get(networkId));
return ImmutableSet.copyOf(virtualPortSet);
}
/**
* Listener class to map listener set events to the virtual network events.
*/
private class InternalSetListener implements SetEventListener<TenantId> {
@Override
public void event(SetEvent<TenantId> event) {
VirtualNetworkEvent.Type type = null;
switch (event.type()) {
case ADD:
type = VirtualNetworkEvent.Type.TENANT_REGISTERED;
break;
case REMOVE:
type = VirtualNetworkEvent.Type.TENANT_UNREGISTERED;
break;
default:
log.error("Unsupported event type: " + event.type());
}
notifyDelegate(new VirtualNetworkEvent(type, null));
}
}
/**
* Listener class to map listener map events to the virtual network events.
*/
private class InternalMapListener implements MapEventListener<NetworkId, VirtualNetwork> {
@Override
public void event(MapEvent<NetworkId, VirtualNetwork> event) {
NetworkId networkId = checkNotNull(event.key());
VirtualNetworkEvent.Type type = null;
switch (event.type()) {
case INSERT:
type = VirtualNetworkEvent.Type.NETWORK_ADDED;
break;
case UPDATE:
if ((event.oldValue().value() != null) && (event.newValue().value() == null)) {
type = VirtualNetworkEvent.Type.NETWORK_REMOVED;
} else {
type = VirtualNetworkEvent.Type.NETWORK_UPDATED;
}
break;
case REMOVE:
type = VirtualNetworkEvent.Type.NETWORK_REMOVED;
break;
default:
log.error("Unsupported event type: " + event.type());
}
notifyDelegate(new VirtualNetworkEvent(type, networkId));
}
}
}
......