From 126ca322499508bb6ae1daa5add829c8d93e5758 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 19 Apr 2016 09:22:19 +0200 Subject: [PATCH] Basic neutron IT netvirt test Tests that flows are properly created for a neutron network with a dhcp and two "vms" Change-Id: Ibbb0fc5eef323ee9ed3bb245fe8e1f6f07a19430 Signed-off-by: Josh --- .../openstack/netvirt/it/NetvirtIT.java | 100 +++++++++-- .../netvirt/impl/SecurityServicesImpl.java | 4 - .../utils/mdsal/openflow/FlowUtils.java | 22 +++ utils/netvirt-it-utils/pom.xml | 7 +- .../netvirt/it/utils/NetvirtItUtils.java | 29 ++++ .../netvirt/it/utils/NeutronNetItUtil.java | 159 ++++++++++++++++++ .../utils/neutron/utils/NeutronUtils.java | 19 +++ 7 files changed, 318 insertions(+), 22 deletions(-) create mode 100644 utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NeutronNetItUtil.java diff --git a/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtIT.java b/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtIT.java index 5a2a68e91d..6ac8085f49 100644 --- a/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtIT.java +++ b/openstack/net-virt-it/src/test/java/org/opendaylight/netvirt/openstack/netvirt/it/NetvirtIT.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Assert; @@ -42,6 +43,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.netvirt.utils.netvirt.it.utils.NetvirtItUtils; +import org.opendaylight.netvirt.utils.netvirt.it.utils.NeutronNetItUtil; import org.opendaylight.netvirt.utils.neutron.utils.NeutronUtils; import org.opendaylight.neutron.spi.INeutronPortCRUD; import org.opendaylight.neutron.spi.INeutronSecurityGroupCRUD; @@ -59,7 +61,6 @@ import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.PipelineO import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service; import org.opendaylight.ovsdb.utils.ovsdb.it.utils.OvsdbItUtils; import org.opendaylight.ovsdb.utils.ovsdb.it.utils.NodeInfo; -import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils; import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils; import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper; import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils; @@ -481,6 +482,7 @@ public class NetvirtIT extends AbstractMdsalTestBase { nodeInfo.connect(); LOG.info("testNetVirtFixedSG: should be connected: {}", nodeInfo.ovsdbNode.getNodeId()); + //TBD: This should be a utility function // Verify the minimum version required for this test OvsdbNodeAugmentation ovsdbNodeAugmentation = nodeInfo.ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class); Assert.assertNotNull(ovsdbNodeAugmentation); @@ -496,6 +498,7 @@ public class NetvirtIT extends AbstractMdsalTestBase { return; } + //TBD: Use NeutronNetItUtil NeutronNetwork nn = neutronUtils.createNeutronNetwork(networkId, tenantId, NetworkHandler.NETWORK_TYPE_VXLAN, "100"); NeutronSubnet ns = neutronUtils.createNeutronSubnet(subnetId, tenantId, networkId, "10.0.0.0/24"); @@ -523,6 +526,11 @@ public class NetvirtIT extends AbstractMdsalTestBase { testDefaultSG(nport, nodeInfo.datapathId, nn, tenantId, portId); Thread.sleep(1000); + assertTrue(neutronUtils.removeNeutronPort(dhcp.getID())); + assertTrue(neutronUtils.removeNeutronPort(nport.getID())); + assertTrue(neutronUtils.removeNeutronSubnet(ns.getID())); + assertTrue(neutronUtils.removeNeutronNetwork(nn.getID())); + nodeInfo.disconnect(); } @@ -585,24 +593,82 @@ public class NetvirtIT extends AbstractMdsalTestBase { flowId = "Ingress_IP" + nn.getProviderSegmentationID() + "_" + nport.getMacAddress() + "_Permit_"; nvItUtils.verifyFlow(datapathId, flowId, pipelineOrchestrator.getTable(Service.INGRESS_ACL)); + + ineutronSecurityGroupCRUD.remove(neutronSG.getID()); + ineutronSecurityRuleCRUD.removeNeutronSecurityRule(nsrEG.getID()); + ineutronSecurityRuleCRUD.removeNeutronSecurityRule(nsrIN.getID()); } - private Flow getFlow ( - FlowBuilder flowBuilder, - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder, - LogicalDatastoreType store) throws InterruptedException { - - Flow flow = null; - for (int i = 0; i < 10; i++) { - LOG.info("getFlow try {} from {}: looking for flow: {}, node: {}", - i, store, flowBuilder.build(), nodeBuilder.build()); - flow = FlowUtils.getFlow(flowBuilder, nodeBuilder, dataBroker.newReadOnlyTransaction(), store); - if (flow != null) { - LOG.info("getFlow try {} from {}: found flow: {}", i, store, flow); - break; - } - Thread.sleep(1000); + /** + * Test a basic neutron use case. This test constructs a Neutron network, subnet, dhcp port, and two "vm" ports + * and validates that the correct flows are installed on OVS. + * @throws InterruptedException if we're interrupted while waiting for some mdsal operation to complete + */ + @Test + public void testNeutronNet() throws InterruptedException { + LOG.warn("testNetWithTwoVms: starting test"); + ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr); + NodeInfo nodeInfo = itUtils.createNodeInfo(connectionInfo, null); + nodeInfo.connect(); + LOG.warn("testNetWithTwoVms: should be connected: {}", nodeInfo.ovsdbNode.getNodeId()); + + // Create the objects + NeutronNetItUtil net = new NeutronNetItUtil(southboundUtils, UUID.randomUUID().toString()); + net.create(); + net.createPort(nodeInfo.bridgeNode, "dhcp", "network:dhcp"); + net.createPort(nodeInfo.bridgeNode, "vm1"); + net.createPort(nodeInfo.bridgeNode, "vm2"); + + + // Check flows created for all ports + for (int i = 1; i <= net.neutronPorts.size(); i++) { + nvItUtils.verifyFlow(nodeInfo.datapathId, "DropFilter_" + i, + pipelineOrchestrator.getTable(Service.CLASSIFIER)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "LocalMac_" + net.segId + "_" + i + "_" + net.macFor(i), + pipelineOrchestrator.getTable(Service.CLASSIFIER)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "ArpResponder_" + net.segId + "_" + net.ipFor(i), + pipelineOrchestrator.getTable(Service.ARP_RESPONDER)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "UcastOut_" + net.segId + "_" + i + "_" + net.macFor(i), + pipelineOrchestrator.getTable(Service.L2_FORWARDING)); + } + + // Check flows created for vm ports only + for (int i = 2; i <= net.neutronPorts.size(); i++) { + nvItUtils.verifyFlow(nodeInfo.datapathId, "Ingress_ARP_" + net.segId + "_" + i + "_", + pipelineOrchestrator.getTable(Service.INGRESS_ACL)); + + nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_Allow_VM_IP_MAC_" + i + net.macFor(i) + "_Permit_", + pipelineOrchestrator.getTable(Service.EGRESS_ACL)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_ARP_" + net.segId + "_" + i + "_", + pipelineOrchestrator.getTable(Service.EGRESS_ACL)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCP_Server_" + i + "_DROP_", + pipelineOrchestrator.getTable(Service.EGRESS_ACL)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCPv6_Server_" + i + "_DROP_", + pipelineOrchestrator.getTable(Service.EGRESS_ACL)); } - return flow; + + // Check ingress/egress acl flows for DHCP + nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCP_Client_Permit_", + pipelineOrchestrator.getTable(Service.EGRESS_ACL)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "Egress_DHCPv6_Client_Permit_", + pipelineOrchestrator.getTable(Service.EGRESS_ACL)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "Ingress_DHCPv6_Server" + net.segId + "_" + + net.macFor(1) + "_Permit_", pipelineOrchestrator.getTable(Service.INGRESS_ACL)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "Ingress_DHCP_Server" + net.segId + "_" + + net.macFor(1) + "_Permit_", pipelineOrchestrator.getTable(Service.INGRESS_ACL)); + + // Check l2 broadcast flows + nvItUtils.verifyFlow(nodeInfo.datapathId, "TunnelFloodOut_" + net.segId, + pipelineOrchestrator.getTable(Service.L2_FORWARDING)); + nvItUtils.verifyFlow(nodeInfo.datapathId, "BcastOut_" + net.segId, + pipelineOrchestrator.getTable(Service.L2_FORWARDING)); + + //TBD Figure out why this does not work: + //nvItUtils.verifyFlow(nodeInfo.datapathId, "TunnelMiss_" + net.segId, + // pipelineOrchestrator.getTable(Service.L2_FORWARDING)); + + net.destroy(); + nodeInfo.disconnect(); } + } diff --git a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImpl.java index 67f0e8d1e5..e853b4843a 100644 --- a/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImpl.java +++ b/openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityServicesImpl.java @@ -152,10 +152,6 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa if (neutronPort.getDeviceOwner().contains("dhcp")) { return neutronPort; } - /* if the current port is a DHCP port, return the same*/ - if (neutronPort.getDeviceOwner().contains("dhcp")) { - return neutronPort; - } /*Since all the fixed ip assigned to a port should be *from the same network, first port is sufficient.*/ List fixedIps = neutronPort.getFixedIPs(); diff --git a/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/FlowUtils.java b/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/FlowUtils.java index 203f20bafe..3335586bef 100644 --- a/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/FlowUtils.java +++ b/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/FlowUtils.java @@ -79,6 +79,13 @@ public class FlowUtils { .child(Flow.class, flowBuilder.getKey()).build(); } + public static InstanceIdentifier createTablePath(NodeBuilder nodeBuilder, short table) { + return InstanceIdentifier.builder(Nodes.class) + .child(Node.class, nodeBuilder.getKey()) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(table)).build(); + } + public static InstanceIdentifier createNodePath(NodeBuilder nodeBuilder) { return InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeBuilder.getKey()).build(); } @@ -98,6 +105,21 @@ public class FlowUtils { return null; } + public static Table getTable(NodeBuilder nodeBuilder, short table, + ReadOnlyTransaction readTx, final LogicalDatastoreType store) { + try { + Optional
data = readTx.read(store, createTablePath(nodeBuilder, table)).get(); + if (data.isPresent()) { + return data.get(); + } + } catch (InterruptedException|ExecutionException e) { + LOG.error("Failed to get table {}", table, e); + } + + LOG.info("Cannot find data for table {} in {}", table, store); + return null; + } + public static FlowBuilder getPipelineFlow(short table, short gotoTable) { FlowBuilder flowBuilder = new FlowBuilder(); flowBuilder.setMatch(new MatchBuilder().build()); diff --git a/utils/netvirt-it-utils/pom.xml b/utils/netvirt-it-utils/pom.xml index 59b7c002d6..64f65ad325 100644 --- a/utils/netvirt-it-utils/pom.xml +++ b/utils/netvirt-it-utils/pom.xml @@ -44,9 +44,14 @@ and is available at http://www.eclipse.org/legal/epl-v10.html utils.mdsal-utils${project.version} + + ${project.groupId} + utils.neutron-utils + ${project.version} + org.opendaylight.ovsdb - utils.mdsal-utils + utils.mdsal-utils ${ovsdb.version} diff --git a/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NetvirtItUtils.java b/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NetvirtItUtils.java index 2e694b402c..41dcb05e58 100644 --- a/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NetvirtItUtils.java +++ b/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NetvirtItUtils.java @@ -18,6 +18,7 @@ import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils; import org.opendaylight.ovsdb.utils.mdsal.utils.NotifyingDataChangeListener; import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; @@ -107,6 +108,34 @@ public class NetvirtItUtils { flow); } + /** + * Log the flows in a given table. + * @param datapathId dpid + * @param tableNum table number + * @param store configuration or operational + */ + public void logFlows(long datapathId, short tableNum, LogicalDatastoreType store) { + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder = + FlowUtils.createNodeBuilder(datapathId); + Table table = FlowUtils.getTable(nodeBuilder, tableNum, dataBroker.newReadOnlyTransaction(), store); + if (table == null) { + LOG.info("logFlows: Could not find table {} in {}", tableNum, store); + } + //TBD: Log table and store in one line, flows in following lines + for (Flow flow : table.getFlow()) { + LOG.info("logFlows: table {} flow {} in {}", tableNum, flow.getFlowName(), store); + } + } + + /** + * Log the flows in a given table. + * @param datapathId dpid + * @param table table number + */ + public void logFlows(long datapathId, short table) { + logFlows(datapathId, table, LogicalDatastoreType.CONFIGURATION); + } + /** * Get a DataBroker and assert that it is not null. * @param providerContext ProviderContext from which to retrieve the DataBroker diff --git a/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NeutronNetItUtil.java b/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NeutronNetItUtil.java new file mode 100644 index 0000000000..2b5cdbfcaa --- /dev/null +++ b/utils/netvirt-it-utils/src/main/java/org/opendaylight/netvirt/utils/netvirt/it/utils/NeutronNetItUtil.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.netvirt.utils.netvirt.it.utils; + +import java.util.Map; +import java.util.UUID; +import java.util.Vector; + +import com.google.common.collect.Maps; +import org.junit.Assert; +import org.opendaylight.netvirt.utils.neutron.utils.NeutronUtils; +import org.opendaylight.neutron.spi.NeutronNetwork; +import org.opendaylight.neutron.spi.NeutronPort; +import org.opendaylight.neutron.spi.NeutronSubnet; +import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; + +/** + * A utility class used in integration tests that need to create neutron networks with some ports. + * Please see NetvirtIT#testNeutronNet for an example of how this class is used + */ +public class NeutronNetItUtil { + + public final String tenantId; + public final String id; + public final String subnetId; + public NeutronNetwork neutronNetwork; + public NeutronSubnet neutronSubnet; + public String segId = "100"; + public String macPfx; + public String ipPfx; + public String cidr; + + public SouthboundUtils southboundUtils; + public NeutronUtils neutronUtils; + public Vector neutronPorts = new Vector(); + + /** + * Construct a new NeutronNetItUtil. + * @param southboundUtils used to create termination points + * @param tenantId tenant ID + */ + public NeutronNetItUtil(SouthboundUtils southboundUtils, String tenantId) { + this(southboundUtils, tenantId, "101", "f7:00:00:0f:00:", "10.0.0.", "10.0.0.0/24"); + } + + /** + * Construct a new NeutronNetItUtil. + * @param southboundUtils used to create termination points + * @param tenantId tenant ID + * @param segId the segmentation id to use for the neutron network + * @param macPfx the first characters of the mac addresses generated for ports. Format is "f7:00:00:0f:00:" + * @param ipPfx the first characters of the ip addresses generated for ports. Format is "10.0.0." + * @param cidr the cidr for this network, e.g., "10.0.0.0/24" + */ + public NeutronNetItUtil(SouthboundUtils southboundUtils, String tenantId, + String segId, String macPfx, String ipPfx, String cidr) { + this.tenantId = tenantId; + this.segId = segId; + this.macPfx = macPfx; + this.ipPfx = ipPfx; + this.cidr = cidr; + + this.id = UUID.randomUUID().toString(); + this.subnetId = UUID.randomUUID().toString(); + + this.southboundUtils = southboundUtils; + neutronUtils = new NeutronUtils(); + neutronNetwork = null; + neutronSubnet = null; + } + + /** + * Create the network and subnet. + */ + public void create() { + neutronNetwork = neutronUtils.createNeutronNetwork(id, tenantId, "vxlan", segId); + neutronSubnet = neutronUtils.createNeutronSubnet(subnetId, tenantId, id, "10.0.0.0/24"); + } + + /** + * Clean up all created neutron objects. + */ + public void destroy() { + for (NeutronPort port : neutronPorts) { + neutronUtils.removeNeutronPort(port.getID()); + } + neutronPorts.clear(); + + if (neutronSubnet != null) { + neutronUtils.removeNeutronSubnet(neutronSubnet.getID()); + neutronSubnet = null; + } + + if (neutronNetwork != null) { + neutronUtils.removeNeutronNetwork(neutronNetwork.getID()); + neutronNetwork = null; + } + } + + /** + * Create a port on the network. The deviceOwner will be set to "compute:None". + * @param bridge bridge where the port will be created on OVS + * @param portName name for this port + * @throws InterruptedException if we're interrupted while waiting for objects to be created + */ + public void createPort(Node bridge, String portName) throws InterruptedException { + createPort(bridge, portName, "compute:None"); + } + + /** + * Create a port on the network. The deviceOwner will be set to "compute:None". + * @param bridge bridge where the port will be created on OVS + * @param portName name for this port + * @param owner deviceOwner, e.g., "network:dhcp" + * @throws InterruptedException if we're interrupted while waiting for objects to be created + */ + public void createPort(Node bridge, String portName, String owner) throws InterruptedException { + long idx = neutronPorts.size() + 1; + Assert.assertTrue(idx < 256); + String mac = macFor(idx); + String ip = ipFor(idx); + String portId = UUID.randomUUID().toString(); + neutronPorts.add(neutronUtils.createNeutronPort(id, subnetId, portId, owner, ip, mac)); + + //TBD: Use NotifyingDataChangeListener + Thread.sleep(1000); + + Map externalIds = Maps.newHashMap(); + externalIds.put("attached-mac", mac); + externalIds.put("iface-id", portId); + southboundUtils.addTerminationPoint(bridge, portName, "internal", null, externalIds, idx); + } + + /** + * Get the mac address for the n'th port created on this network (starts at 1). + * @param portNum index of port created + * @return the mac address + */ + public String macFor(long portNum) { + return macPfx + String.format("%02x", portNum); + } + + /** + * Get the ip address for the n'th port created on this network (starts at 1). + * @param portNum index of port created + * @return the mac address + */ + public String ipFor(long portNum) { + return ipPfx + portNum; + } +} + diff --git a/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronUtils.java b/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronUtils.java index c1fd40dc43..b7a48c5168 100644 --- a/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronUtils.java +++ b/utils/neutron-utils/src/main/java/org/opendaylight/netvirt/utils/neutron/utils/NeutronUtils.java @@ -43,6 +43,12 @@ public class NeutronUtils { return np; } + public boolean removeNeutronPort(String uuid) { + INeutronPortCRUD iNeutronPortCRUD = + (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this); + return iNeutronPortCRUD.removePort(uuid); + } + public NeutronSubnet createNeutronSubnet(String subnetId, String tenantId, String networkId, String cidr) { INeutronSubnetCRUD iNeutronSubnetCRUD = @@ -57,6 +63,12 @@ public class NeutronUtils { return ns; } + public boolean removeNeutronSubnet(String uuid) { + INeutronSubnetCRUD iNeutronSubnetCRUD = + (INeutronSubnetCRUD) ServiceHelper.getGlobalInstance(INeutronSubnetCRUD.class, this); + return iNeutronSubnetCRUD.removeSubnet(uuid); + } + public NeutronNetwork createNeutronNetwork(String uuid, String tenantID, String networkTypeVxlan, String segId) { INeutronNetworkCRUD iNeutronNetworkCRUD = (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this); @@ -69,4 +81,11 @@ public class NeutronUtils { iNeutronNetworkCRUD.addNetwork(nn); return nn; } + + public boolean removeNeutronNetwork(String uuid) { + INeutronNetworkCRUD iNeutronNetworkCRUD = + (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this); + return iNeutronNetworkCRUD.removeNetwork(uuid); + + } } -- 2.36.6