From b0a91e949a5397aeae8751266b6f4c8f5bde335f Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Wed, 1 Jun 2016 17:42:42 +0200 Subject: [PATCH] Implementing VPP Renderer registration Change-Id: I516aa14fd96f0931dfd3a1e60a40c0cdec6b041a Signed-off-by: Michal Cmarada --- features/src/main/features/features.xml | 1 + renderers/vpp/pom.xml | 27 ++- .../vpp/src/main/config/default-config.xml | 4 + .../impl/GbpVppProviderModule.java | 2 +- .../config/vpp_provider/impl/VppRenderer.java | 164 ++++++++++--- .../vpp/listener/VppNodeListener.java | 69 ++++++ .../renderer/vpp/manager/VppNodeManager.java | 229 ++++++++++++++++++ .../renderer/vpp/sf/Action.java | 46 ++++ .../renderer/vpp/sf/AllowAction.java | 47 ++++ .../renderer/vpp/sf/Classifier.java | 72 ++++++ .../renderer/vpp/sf/EtherTypeClassifier.java | 70 ++++++ .../renderer/vpp/sf/IpProtoClassifier.java | 92 +++++++ .../renderer/vpp/util/General.java | 63 ++--- .../renderer/vpp/util/VppIidFactory.java | 39 +++ .../renderer/vpp/util/VppNodeWriter.java | 90 +++++++ .../vpp/src/main/yang/vpp-provider-impl.yang | 9 + .../vpp/VppRendererDataBrokerTest.java | 8 +- .../vpp/manager/VppManagerDataStoreTest.java | 159 ++++++++++++ .../renderer/vpp/util/VppNodeWriterTest.java | 94 +++++++ 19 files changed, 1217 insertions(+), 68 deletions(-) create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppNodeManager.java create mode 100755 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Action.java create mode 100755 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/AllowAction.java create mode 100755 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Classifier.java create mode 100755 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/EtherTypeClassifier.java create mode 100755 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/IpProtoClassifier.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriter.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriterTest.java diff --git a/features/src/main/features/features.xml b/features/src/main/features/features.xml index 591ed7fc0..c1497cd6a 100755 --- a/features/src/main/features/features.xml +++ b/features/src/main/features/features.xml @@ -156,6 +156,7 @@ --> odl-groupbasedpolicy-base + odl-netconf-topology mvn:org.opendaylight.groupbasedpolicy/l2-l3-domain-extension/{{VERSION}} mvn:org.opendaylight.groupbasedpolicy/vpp-renderer/{{VERSION}} mvn:org.opendaylight.groupbasedpolicy/l2-l3-domain-extension/{{VERSION}}/xml/config diff --git a/renderers/vpp/pom.xml b/renderers/vpp/pom.xml index 3ea402b0c..6ff00a804 100644 --- a/renderers/vpp/pom.xml +++ b/renderers/vpp/pom.xml @@ -17,7 +17,28 @@ vpp-renderer bundle - + + 1.1.0-SNAPSHOT + + + + + + org.opendaylight.netconf + netconf-artifacts + ${netconf.version} + pom + import + + + org.opendaylight.controller + mdsal-artifacts + ${mdsal.version} + pom + import + + + @@ -41,6 +62,10 @@ org.opendaylight.mdsal.model ietf-interfaces + + org.opendaylight.netconf + sal-netconf-connector + diff --git a/renderers/vpp/src/main/config/default-config.xml b/renderers/vpp/src/main/config/default-config.xml index baff11b49..8049bcfaa 100644 --- a/renderers/vpp/src/main/config/default-config.xml +++ b/renderers/vpp/src/main/config/default-config.xml @@ -20,6 +20,10 @@ binding:binding-async-data-broker binding-data-broker + + binding:binding-broker-osgi-registry + binding-osgi-broker + diff --git a/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/GbpVppProviderModule.java b/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/GbpVppProviderModule.java index cb462bdb4..744f116c9 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/GbpVppProviderModule.java +++ b/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/GbpVppProviderModule.java @@ -30,7 +30,7 @@ public class GbpVppProviderModule extends org.opendaylight.controller.config.yan @Override public java.lang.AutoCloseable createInstance() { - final VppRenderer vppRenderer = new VppRenderer(getDataBrokerDependency()); + final VppRenderer vppRenderer = new VppRenderer(getDataBrokerDependency(), getBrokerDependency()); LOG.info("VPP Renderer instance has been created"); diff --git a/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java b/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java index f3885f2d3..d0e9ac411 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java +++ b/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java @@ -1,34 +1,130 @@ -/* - * Copyright (c) 2014 Cisco Systems, 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.controller.config.yang.config.vpp_provider.impl; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class VppRenderer implements AutoCloseable { - private static final Logger LOG = LoggerFactory.getLogger(VppRenderer.class); - - private DataBroker dataBroker; - - public VppRenderer(DataBroker dataBroker) { - Preconditions.checkNotNull(dataBroker); - - this.dataBroker = dataBroker; - - LOG.info("VPP Renderer has Started"); - } - - @Override - public void close() throws Exception { - this.dataBroker = null; - } - -} +/* + * Copyright (c) 2014 Cisco Systems, 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.controller.config.yang.config.vpp_provider.impl; + +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppNodeListener; +import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager; +import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.AllowAction; +import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.EtherTypeClassifier; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.CapabilitiesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedActionDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedActionDefinitionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedClassifierDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.SupportedClassifierDefinitionBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +public class VppRenderer implements AutoCloseable, BindingAwareProvider { + + private static final Logger LOG = LoggerFactory.getLogger(VppRenderer.class); + + private final List actionDefinitions = + ImmutableList.of(new SupportedActionDefinitionBuilder().setActionDefinitionId(new AllowAction().getId()) + .setSupportedParameterValues(new AllowAction().getSupportedParameterValues()) + .build()); + private final List classifierDefinitions = ImmutableList + .of(new SupportedClassifierDefinitionBuilder().setClassifierDefinitionId(new EtherTypeClassifier(null).getId()) + .setSupportedParameterValues(new EtherTypeClassifier(null).getSupportedParameterValues()) + .build()); + + private DataBroker dataBroker; + private VppNodeManager vppNodeManager; + private VppNodeListener vppNodeListener; + + public VppRenderer(DataBroker dataBroker, BindingAwareBroker bindingAwareBroker) { + this.dataBroker = Preconditions.checkNotNull(dataBroker); + bindingAwareBroker.registerProvider(this); + } + + @Override + public void close() throws Exception { + LOG.info("Closing Vpp renderer"); + if (vppNodeListener != null) { + vppNodeListener.close(); + } + unregisterFromRendererManager(); + } + + @Override + public void onSessionInitiated(BindingAwareBroker.ProviderContext providerContext) { + LOG.info("starting vpp renderer"); + + // vpp-node-manager + vppNodeManager = new VppNodeManager(dataBroker, providerContext); + vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager); + + registerToRendererManager(); + } + + private void registerToRendererManager() { + WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); + + Renderer renderer = new RendererBuilder().setName(VppNodeManager.vppRenderer) + .setRendererNodes(new RendererNodesBuilder().build()) + .setCapabilities(new CapabilitiesBuilder().setSupportedActionDefinition(actionDefinitions) + .setSupportedClassifierDefinition(classifierDefinitions) + .build()) + .build(); + + writeTransaction.put(LogicalDatastoreType.OPERATIONAL, VppIidFactory.getRendererIID(renderer.getKey()), + renderer, true); + CheckedFuture future = writeTransaction.submit(); + Futures.addCallback(future, new FutureCallback() { + + @Override + public void onFailure(Throwable throwable) { + LOG.error("Could not register renderer {}: {}", renderer, throwable); + } + + @Override + public void onSuccess(Void result) { + LOG.debug("Renderer {} successfully registered.", renderer); + } + }); + } + + + private void unregisterFromRendererManager() { + WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); + writeTransaction.delete(LogicalDatastoreType.OPERATIONAL, VppIidFactory.getRendererIID(new RendererKey(VppNodeManager.vppRenderer))); + + CheckedFuture future = writeTransaction.submit(); + Futures.addCallback(future, new FutureCallback() { + + @Override + public void onFailure(Throwable throwable) { + LOG.error("Could not unregister renderer {}: {}", VppNodeManager.vppRenderer, throwable); + } + + @Override + public void onSuccess(Void result) { + LOG.debug("Renderer {} successfully unregistered.", VppNodeManager.vppRenderer); + } + }); + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java new file mode 100644 index 000000000..df39b165f --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.listener; + +import java.util.Collection; + +import javax.annotation.Nonnull; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +public class VppNodeListener implements DataTreeChangeListener, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(VppNodeListener.class); + + private final ListenerRegistration listenerRegistration; + private final VppNodeManager nodeManager; + + public VppNodeListener(DataBroker dataBroker, VppNodeManager nodeManager) { + this.nodeManager = Preconditions.checkNotNull(nodeManager); + // Register listener + final DataTreeIdentifier networkTopologyPath = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, + InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).child(Node.class).build()); + listenerRegistration = + Preconditions.checkNotNull(dataBroker.registerDataTreeChangeListener(networkTopologyPath, this)); + LOG.info("Network-Topology VppNodelistener registered"); + } + + @Override + public void onDataTreeChanged(@Nonnull Collection> changes) { + LOG.debug("Topology Node changed. Changes {}", changes); + + for (DataTreeModification modification : changes) { + DataObjectModification rootNode = modification.getRootNode(); + Node dataAfter = rootNode.getDataAfter(); + Node dataBefore = rootNode.getDataBefore(); + nodeManager.syncNodes(dataAfter, dataBefore); + } + } + + public ListenerRegistration getRegistrationObject() { + return listenerRegistration; + } + + @Override + public void close() throws Exception { + listenerRegistration.close(); + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppNodeManager.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppNodeManager.java new file mode 100644 index 000000000..ba0ef5ab8 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppNodeManager.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2016 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.manager; + +import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connected; +import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connecting; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.MountPoint; +import org.opendaylight.controller.md.sal.binding.api.MountPointService; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppNodeWriter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +public class VppNodeManager { + + public static final RendererName vppRenderer = new RendererName("vpp-renderer"); + private static final TopologyId TOPOLOGY_ID = new TopologyId("topology-netconf"); + private static final Logger LOG = LoggerFactory.getLogger(VppNodeManager.class); + private static final Map, DataBroker> netconfNodeCache = new HashMap<>(); + private static final String V3PO_CAPABILITY = "(urn:opendaylight:params:xml:ns:yang:v3po?revision=2015-01-05)v3po"; + private static final String INTERFACES_CAPABILITY = + "(urn:ietf:params:xml:ns:yang:ietf-interfaces?revision=2014-05-08)ietf-interfaces"; + private final DataBroker dataBroker; + private final MountPointService mountService; + private final List requiredCapabilities; + + public VppNodeManager(DataBroker dataBroker, BindingAwareBroker.ProviderContext session) { + this.dataBroker = Preconditions.checkNotNull(dataBroker); + mountService = Preconditions.checkNotNull(session.getSALService(MountPointService.class)); + requiredCapabilities = initializeRequiredCapabilities(); + } + + static DataBroker getDataBrokerFromCache(InstanceIdentifier iid) { + return netconfNodeCache.get(iid); // TODO read from DS + } + + /** + * Synchronizes nodes to DataStore based on their modification state which results in + * create/update/remove of Node. + */ + public void syncNodes(Node dataAfter, Node dataBefore) { + // New node + if (dataBefore == null && dataAfter != null) { + createNode(dataAfter); + } + // Connected/disconnected node + if (dataBefore != null && dataAfter != null) { + updateNode(dataAfter); + } + // Removed node + if (dataBefore != null && dataAfter == null) { + removeNode(dataBefore); + } + } + + private void createNode(Node node) { + LOG.info("Registering new node {}", node.getNodeId().getValue()); + NetconfNode netconfNode = getNodeAugmentation(node); + if (netconfNode == null) { + return; + } + NetconfNodeConnectionStatus.ConnectionStatus connectionStatus = netconfNode.getConnectionStatus(); + switch (connectionStatus) { + case Connecting: + LOG.info("Connecting device {} ...", node.getNodeId().getValue()); + break; + case Connected: + resolveConnectedNode(node, netconfNode); + LOG.info("Node {} is capable and ready", node.getNodeId().getValue()); + break; + default: + break; + } + } + + private void updateNode(Node node) { + NetconfNode netconfNode = getNodeAugmentation(node); + if (netconfNode == null || netconfNode.getConnectionStatus() == null) { + return; + } + NetconfNodeConnectionStatus.ConnectionStatus afterNodeStatus = netconfNode.getConnectionStatus(); + if (afterNodeStatus.equals(Connected)) { + resolveConnectedNode(node, netconfNode); + LOG.info("Node {} is capable and ready", node.getNodeId().getValue()); + } + if (afterNodeStatus.equals(Connecting)) { + resolveDisconnectedNode(node); + LOG.info("Node {} has been disconnected, removing from available nodes", node.getNodeId().getValue()); + } + } + + private void removeNode(Node node) { + resolveDisconnectedNode(node); + LOG.info("Node {} has been removed", node.getNodeId().getValue()); + } + + private void resolveConnectedNode(Node node, NetconfNode netconfNode) { + InstanceIdentifier mountPointIid = getMountpointIid(node); + // Mountpoint iid == path in renderer-node + RendererNode rendererNode = remapNode(mountPointIid); + VppNodeWriter vppNodeWriter = new VppNodeWriter(); + vppNodeWriter.cache(rendererNode); + if (!isCapableNetconfDevice(node, netconfNode)) { + return; + } + vppNodeWriter.commitToDatastore(dataBroker); + DataBroker mountpoint = getNodeMountPoint(mountPointIid); + netconfNodeCache.put(mountPointIid, mountpoint); + } + + private void resolveDisconnectedNode(Node node) { + InstanceIdentifier mountPointIid = getMountpointIid(node); + RendererNode rendererNode = remapNode(mountPointIid); + VppNodeWriter vppNodeWriter = new VppNodeWriter(); + vppNodeWriter.cache(rendererNode); + vppNodeWriter.removeFromDatastore(dataBroker); + netconfNodeCache.remove(mountPointIid); + } + + private RendererNode remapNode(InstanceIdentifier path) { + RendererNodeBuilder rendererNodeBuilder = new RendererNodeBuilder(); + rendererNodeBuilder.setKey(new RendererNodeKey(path)).setNodePath(path); + return rendererNodeBuilder.build(); + } + + private InstanceIdentifier getMountpointIid(Node node) { + return InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, new TopologyKey(TOPOLOGY_ID)) + .child(Node.class, new NodeKey(node.getNodeId())) + .build(); + } + + private boolean isCapableNetconfDevice(Node node, NetconfNode netconfAugmentation) { + if (netconfAugmentation.getAvailableCapabilities() == null + || netconfAugmentation.getAvailableCapabilities().getAvailableCapability() == null + || netconfAugmentation.getAvailableCapabilities().getAvailableCapability().isEmpty()) { + LOG.warn("Node {} does not contain any capabilities", node.getNodeId().getValue()); + return false; + } + if (!capabilityCheck(netconfAugmentation.getAvailableCapabilities().getAvailableCapability())) { + LOG.warn("Node {} does not contain all capabilities required by vpp-renderer", node.getNodeId().getValue()); + return false; + } + return true; + } + + private boolean capabilityCheck(final List capabilities) { + for (String requiredCapability : requiredCapabilities) { + if (!capabilities.contains(requiredCapability)) { + return false; + } + } + return true; + } + + private DataBroker getNodeMountPoint(InstanceIdentifier mountPointIid) { + Optional optionalObject = mountService.getMountPoint(mountPointIid); + MountPoint mountPoint; + if (optionalObject.isPresent()) { + mountPoint = optionalObject.get(); + if (mountPoint != null) { + Optional optionalDataBroker = mountPoint.getService(DataBroker.class); + if (optionalDataBroker.isPresent()) { + return optionalDataBroker.get(); + } else { + LOG.debug("Cannot obtain data broker from mountpoint {}", mountPoint); + } + } else { + LOG.debug("Cannot obtain mountpoint with IID {}", mountPointIid); + } + } + return null; + } + + private NetconfNode getNodeAugmentation(Node node) { + NetconfNode netconfNode = node.getAugmentation(NetconfNode.class); + if (netconfNode == null) { + LOG.warn("Node {} is not a netconf device", node.getNodeId().getValue()); + return null; + } + return netconfNode; + } + + /** + * Initialize all common capabilities required by VPP renderer. Any connected node is examined + * whether it's + * an appropriate device to handle configuration created by this renderer. A device must support + * all capabilities + * in list below. + * + * @return list of string representations of required capabilities + */ + private List initializeRequiredCapabilities() { + // Required device capabilities + + String[] capabilityEntries = {V3PO_CAPABILITY, INTERFACES_CAPABILITY}; + return Arrays.asList(capabilityEntries); + } + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Action.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Action.java new file mode 100755 index 000000000..e5b4cd3f1 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Action.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.sf; + +import java.util.List; + +import org.opendaylight.groupbasedpolicy.api.Validator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.action.definition.SupportedParameterValues; + +/** + * Represent an action definition, and provide tools for generating + * flow instructions based on the action. + */ +public abstract class Action implements Validator { + + /** + * Get the action definition for this action. + * + * @return the {@link ActionDefinition} for this action + */ + public abstract ActionDefinitionId getId(); + + /** + * Get the action definition for this action. + * + * @return the {@link ActionDefinition} for this action + */ + public abstract ActionDefinition getActionDef(); + + /** + * The result represents supported parameters for the action by renderer. + * + * @return list of supported parameters by the action + */ + public abstract List getSupportedParameterValues(); + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/AllowAction.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/AllowAction.java new file mode 100755 index 000000000..1ad169a2f --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/AllowAction.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.sf; + +import java.util.Collections; +import java.util.List; + +import org.opendaylight.groupbasedpolicy.api.ValidationResult; +import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition; +import org.opendaylight.groupbasedpolicy.dto.ValidationResultBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.action.definition.SupportedParameterValues; + +/** + * Allow action. + */ +public class AllowAction extends Action { + + @Override + public ActionDefinitionId getId() { + return AllowActionDefinition.ID; + } + + @Override + public ActionDefinition getActionDef() { + return AllowActionDefinition.DEFINITION; + } + + @Override + public ValidationResult validate(ActionInstance actionInstance) { + return new ValidationResultBuilder().success().build(); + } + + @Override + public List getSupportedParameterValues() { + // allow action definition has no parameter + return Collections.emptyList(); + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Classifier.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Classifier.java new file mode 100755 index 000000000..f6beb860b --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/Classifier.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.sf; + +import java.util.List; +import java.util.Map; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValues; + +/** + * Represent a classifier definition. + */ +public abstract class Classifier { + + protected final Classifier parent; + + public static final EtherTypeClassifier ETHER_TYPE_CL = new EtherTypeClassifier(null); + public static final IpProtoClassifier IP_PROTO_CL = new IpProtoClassifier(ETHER_TYPE_CL); + + protected Classifier(Classifier parent) { + this.parent = parent; + } + + /** + * Get the classifier definition id for this classifier. + * + * @return the {@link ClassifierDefinitionId} for this classifier + */ + public abstract ClassifierDefinitionId getId(); + + /** + * Get the classifier definition for this classifier. + * + * @return the {@link ClassifierDefinition} for this classifier + */ + public abstract ClassifierDefinition getClassifierDefinition(); + + /** + * Get parent for this classifier. + * + * @return parent classifier, see {@link Classifier} + */ + public final Classifier getParent() { + return parent; + } + + /** + * The result represents supported parameters for the classifier by renderer. + * + * @return list of supported parameters by the classifier + */ + public abstract List getSupportedParameterValues(); + + /** + * Checks presence of required {@code params} in order to decide if classifier can update + * {@code matches} properly. + * + * @param params inserted parameters, not null + * @throws IllegalArgumentException when any of required {@code params} is not present + */ + protected abstract void checkPresenceOfRequiredParams(Map params); + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/EtherTypeClassifier.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/EtherTypeClassifier.java new file mode 100755 index 000000000..447fb1b0f --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/EtherTypeClassifier.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.sf; + +import java.util.List; +import java.util.Map; + +import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.parameters.type.parameter.type.IntBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValues; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValuesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported._int.value.fields.SupportedIntValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported._int.value.fields.SupportedIntValueBuilder; + +import com.google.common.collect.ImmutableList; + +/** + * Match on the ether type of the traffic. + */ +public class EtherTypeClassifier extends Classifier { + + public EtherTypeClassifier(Classifier parent) { + super(parent); + } + + @Override + public ClassifierDefinitionId getId() { + return EtherTypeClassifierDefinition.ID; + } + + @Override + public ClassifierDefinition getClassifierDefinition() { + return EtherTypeClassifierDefinition.DEFINITION; + } + + @Override + public List getSupportedParameterValues() { + + List values = ImmutableList.of( + new SupportedIntValueBuilder().setValue(EtherTypeClassifierDefinition.IPv4_VALUE).build(), + new SupportedIntValueBuilder().setValue(EtherTypeClassifierDefinition.IPv6_VALUE).build()); + SupportedParameterValuesBuilder builder = new SupportedParameterValuesBuilder(); + builder.setParameterName(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)); + builder.setParameterType(new IntBuilder().setSupportedIntValue(values).build()); + + return ImmutableList.of(builder.build()); + } + + @Override + protected void checkPresenceOfRequiredParams(Map params) { + if (params.get(EtherTypeClassifierDefinition.ETHERTYPE_PARAM) == null) { + throw new IllegalArgumentException( + "Parameter " + EtherTypeClassifierDefinition.ETHERTYPE_PARAM + " not specified."); + } + if (params.get(EtherTypeClassifierDefinition.ETHERTYPE_PARAM).getIntValue() == null) { + throw new IllegalArgumentException( + "Value of " + EtherTypeClassifierDefinition.ETHERTYPE_PARAM + " parameter is not present."); + } + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/IpProtoClassifier.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/IpProtoClassifier.java new file mode 100755 index 000000000..019bde00d --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/IpProtoClassifier.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.sf; + +import java.util.List; +import java.util.Map; + +import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.parameters.type.parameter.type.IntBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValues; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValuesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported._int.value.fields.SupportedIntValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported._int.value.fields.SupportedIntValueBuilder; + +import com.google.common.collect.ImmutableList; + +/** + * Match on the IP protocol of IP traffic. + */ +public class IpProtoClassifier extends Classifier { + + protected IpProtoClassifier(Classifier parent) { + super(parent); + } + + @Override + public ClassifierDefinitionId getId() { + return IpProtoClassifierDefinition.ID; + } + + @Override + public ClassifierDefinition getClassifierDefinition() { + return IpProtoClassifierDefinition.DEFINITION; + } + + @Override + public List getSupportedParameterValues() { + + List values = ImmutableList.of( + new SupportedIntValueBuilder().setValue(IpProtoClassifierDefinition.ICMP_VALUE).build(), + new SupportedIntValueBuilder().setValue(IpProtoClassifierDefinition.SCTP_VALUE).build(), + new SupportedIntValueBuilder().setValue(IpProtoClassifierDefinition.TCP_VALUE).build(), + new SupportedIntValueBuilder().setValue(IpProtoClassifierDefinition.UDP_VALUE).build()); + SupportedParameterValuesBuilder builder = new SupportedParameterValuesBuilder(); + builder.setParameterName(new ParameterName(IpProtoClassifierDefinition.PROTO_PARAM)); + builder.setParameterType(new IntBuilder().setSupportedIntValue(values).build()); + + return ImmutableList.of(builder.build()); + } + + @Override + protected void checkPresenceOfRequiredParams(Map params) { + if (params.get(IpProtoClassifierDefinition.PROTO_PARAM) == null) { + throw new IllegalArgumentException( + "Parameter " + IpProtoClassifierDefinition.PROTO_PARAM + " not specified."); + } + if (params.get(IpProtoClassifierDefinition.PROTO_PARAM).getIntValue() == null) { + throw new IllegalArgumentException( + "Value of " + IpProtoClassifierDefinition.PROTO_PARAM + " parameter is not present."); + } + } + + /** + * Return the IpProtocol value. May return null. + * + * @param params the parameters of classifier-instance inserted by user + * @return the IpProtocol value + */ + public static Long getIpProtoValue(Map params) { + if (params == null) { + return null; + } + if (params.get(IpProtoClassifierDefinition.PROTO_PARAM) == null) { + return null; + } + Long proto = params.get(IpProtoClassifierDefinition.PROTO_PARAM).getIntValue(); + if (proto != null) { + return proto; + } + return null; + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/General.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/General.java index ab59e4b1e..41ce17485 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/General.java +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/General.java @@ -1,31 +1,32 @@ -/* - * Copyright (c) 2016 Cisco Systems. 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.groupbasedpolicy.renderer.vpp.util; - - -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class General { - - /** - * Operations that can be executed over ConfigCommand. Operation names reflect operations used in WriteTransaction. - * For more information on these operations, please see the documentation in: - *
- * {@link WriteTransaction#put(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)}
- * {@link WriteTransaction#merge(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)}
- * {@link WriteTransaction#delete(LogicalDatastoreType, InstanceIdentifier)}
- * - */ - public enum Operations { - PUT, DELETE, MERGE - } -} +/* + * Copyright (c) 2016 Cisco Systems. 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.groupbasedpolicy.renderer.vpp.util; + +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class General { + + /** + * Operations that can be executed over ConfigCommand. Operation names reflect operations used + * in WriteTransaction. + * For more information on these operations, please see the documentation in: + *
+ * {@link WriteTransaction#put(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)} + *
+ * {@link WriteTransaction#merge(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)} + *
+ * {@link WriteTransaction#delete(LogicalDatastoreType, InstanceIdentifier)}
+ */ + public enum Operations { + PUT, DELETE, MERGE + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppIidFactory.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppIidFactory.java index 19a672cd3..2e523e832 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppIidFactory.java +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppIidFactory.java @@ -8,9 +8,22 @@ package org.opendaylight.groupbasedpolicy.renderer.vpp.util; +import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; public class VppIidFactory { @@ -18,4 +31,30 @@ public class VppIidFactory { public static InstanceIdentifier getInterfaceIID(InterfaceKey interfaceKey) { return InstanceIdentifier.create(Interfaces.class).child(Interface.class, interfaceKey); } + + public static InstanceIdentifier getRendererIID(RendererKey rendererKey) { + return InstanceIdentifier.create(Renderers.class).child(Renderer.class, rendererKey); + } + + public static InstanceIdentifier getRendererNodesIid() { + return InstanceIdentifier.builder(Renderers.class) + .child(Renderer.class, new RendererKey(VppNodeManager.vppRenderer)) + .child(RendererNodes.class) + .build(); + } + + public static InstanceIdentifier getRendererNodeIid(RendererNode rendererNode) { + return InstanceIdentifier.builder(Renderers.class) + .child(Renderer.class, new RendererKey(VppNodeManager.vppRenderer)) + .child(RendererNodes.class) + .child(RendererNode.class, new RendererNodeKey(rendererNode.getNodePath())) + .build(); + } + + public static InstanceIdentifier getNodeIid(NodeKey key) { + TopologyKey topologyKey = new TopologyKey(new TopologyId("topology-netconf")); + return InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class,topologyKey) + .child(Node.class, key).build(); + } } diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriter.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriter.java new file mode 100644 index 000000000..1e65549ac --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriter.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 Cisco Systems, 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.groupbasedpolicy.renderer.vpp.util; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.CheckedFuture; + +public class VppNodeWriter { + + private static final Logger LOG = LoggerFactory.getLogger(VppNodeWriter.class); + private List rendererNodesCache; + + public VppNodeWriter() { + rendererNodesCache = new ArrayList<>(); + } + + public void cache(RendererNode node) { + rendererNodesCache.add(node); + } + + /** + * Put all cached items to data store. + * + * @param dataBroker appropriate data provider + */ + public void commitToDatastore(DataBroker dataBroker) { + RendererNodes rendererNodes = buildRendererNodes(); + WriteTransaction wtx = dataBroker.newWriteOnlyTransaction(); + InstanceIdentifier iid = VppIidFactory.getRendererNodesIid(); + try { + wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, rendererNodes, true); + CheckedFuture submitFuture = wtx.submit(); + submitFuture.checkedGet(); + // Clear cache + rendererNodesCache.clear(); + } catch (TransactionCommitFailedException e) { + LOG.error("Write transaction failed to {}", e.getMessage()); + } catch (Exception e) { + LOG.error("Failed to .. {}", e.getMessage()); + } + } + + /** + * Removes all cached items from data store. + * + * @param dataBroker appropriate data provider + */ + public void removeFromDatastore(DataBroker dataBroker) { + WriteTransaction wtx = dataBroker.newWriteOnlyTransaction(); + for (RendererNode nodeToRemove : rendererNodesCache) { + InstanceIdentifier iid = VppIidFactory.getRendererNodeIid(nodeToRemove); + try { + wtx.delete(LogicalDatastoreType.OPERATIONAL, iid); + CheckedFuture submitFuture = wtx.submit(); + submitFuture.checkedGet(); + // Clear cache + } catch (TransactionCommitFailedException e) { + LOG.error("Write transaction failed to {}", e.getMessage()); + } catch (Exception e) { + LOG.error("Failed to .. {}", e.getMessage()); + } + } + rendererNodesCache.clear(); + } + + private RendererNodes buildRendererNodes() { + RendererNodesBuilder rendererNodesBuilder = new RendererNodesBuilder(); + rendererNodesBuilder.setRendererNode(new ArrayList<>(rendererNodesCache)); + return rendererNodesBuilder.build(); + } +} diff --git a/renderers/vpp/src/main/yang/vpp-provider-impl.yang b/renderers/vpp/src/main/yang/vpp-provider-impl.yang index 7169ca14a..6401c4b98 100644 --- a/renderers/vpp/src/main/yang/vpp-provider-impl.yang +++ b/renderers/vpp/src/main/yang/vpp-provider-impl.yang @@ -46,6 +46,15 @@ module vpp-provider-impl { } } } + // binding aware broker + container broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-broker-osgi-registry; + } + } + } } } } diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/VppRendererDataBrokerTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/VppRendererDataBrokerTest.java index 8cd7458a0..551f19b83 100644 --- a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/VppRendererDataBrokerTest.java +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/VppRendererDataBrokerTest.java @@ -11,7 +11,12 @@ package org.opendaylight.groupbasedpolicy.renderer.vpp; import com.google.common.collect.ImmutableList; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import javax.annotation.Nonnull; import java.util.Collection; @@ -21,6 +26,7 @@ public class VppRendererDataBrokerTest extends CustomDataBrokerTest { @Nonnull @Override public Collection> getClassesFromModules() { - return ImmutableList.of(Interfaces.class, Interface.class, VhostUser.class); + return ImmutableList.of(Interfaces.class, Interface.class, VhostUser.class, NetworkTopology.class, + Topology.class, Node.class, NetconfNode.class, Renderer.class); } } diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java new file mode 100644 index 000000000..537adc7ed --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java @@ -0,0 +1,159 @@ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.manager; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.controller.md.sal.binding.api.*; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.groupbasedpolicy.renderer.vpp.VppRendererDataBrokerTest; +import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppNodeListener; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilitiesBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test for {@link VppNodeManager} and {@link VppNodeListener}. + */ +@RunWith(MockitoJUnitRunner.class) +public class VppManagerDataStoreTest extends VppRendererDataBrokerTest { + + private static final String V3PO_CAPABILITY = "(urn:opendaylight:params:xml:ns:yang:v3po?revision=2015-01-05)v3po"; + private static final String INTERFACES_CAPABILITY = + "(urn:ietf:params:xml:ns:yang:ietf-interfaces?revision=2014-05-08)ietf-interfaces"; + private static final String NODE_NAME = "testVpp"; + + private final InstanceIdentifier nodeIid = VppIidFactory.getNodeIid(new NodeKey(new NodeId(NODE_NAME))); + + @Mock + BindingAwareBroker.ProviderContext providerContext; + @Mock + MountPointService mountPointService; + @Mock + MountPoint mountPoint; + @Mock + DataBroker dataBroker2; + + private DataBroker dataBroker; + private VppNodeListener vppNodeListener; + private VppNodeManager vppNodeManager; + + @Before + public void setUp() throws Exception { + Mockito.when(providerContext.getSALService(Matchers.>any())) + .thenReturn(mountPointService); + Mockito.when(mountPointService.getMountPoint(Matchers.>any())) + .thenReturn(Optional.of(mountPoint)); + Mockito.when(mountPoint.getService(Matchers.>any())).thenReturn(Optional.of(dataBroker2)); + dataBroker = getDataBroker(); + vppNodeManager = new VppNodeManager(dataBroker, providerContext); + vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager); + } + + private Node createNode(final String name, NetconfNodeConnectionStatus.ConnectionStatus status) { + Host host = new Host(new IpAddress(new Ipv4Address("192.168.255.101"))); + PortNumber portNumber = new PortNumber(2830); + + List avaibleCapabilitiesList = new ArrayList<>(); + avaibleCapabilitiesList.add(V3PO_CAPABILITY); + avaibleCapabilitiesList.add(INTERFACES_CAPABILITY); + + NetconfNode netconfNode = new NetconfNodeBuilder().setHost(host) + .setPort(portNumber) + .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().build()) + .setAvailableCapabilities( + new AvailableCapabilitiesBuilder().setAvailableCapability(avaibleCapabilitiesList).build()) + .setConnectionStatus(status) + .build(); + + return new NodeBuilder().setNodeId(new NodeId(name)).addAugmentation(NetconfNode.class, netconfNode).build(); + } + + @Test + public void connectNode() throws ReadFailedException { + WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); + Node testVppNode = createNode(NODE_NAME, NetconfNodeConnectionStatus.ConnectionStatus.Connected); + + writeTransaction.put(LogicalDatastoreType.OPERATIONAL, nodeIid, testVppNode, true); + + writeTransaction.submit(); + + ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction(); + CheckedFuture, ReadFailedException> future = + readOnlyTransaction.read(LogicalDatastoreType.OPERATIONAL, + VppIidFactory.getRendererIID(new RendererKey(VppNodeManager.vppRenderer))); + Optional rendererOptional = future.checkedGet(); + + Assert.assertTrue(rendererOptional.isPresent()); + Assert.assertEquals(1, rendererOptional.get().getRendererNodes().getRendererNode().size()); + Assert.assertEquals(nodeIid, rendererOptional.get().getRendererNodes().getRendererNode().get(0).getNodePath()); + } + + @Test + public void disconnectNode() throws ReadFailedException, InterruptedException { + WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); + Node testVppNode = createNode(NODE_NAME, NetconfNodeConnectionStatus.ConnectionStatus.Connected); + + writeTransaction.put(LogicalDatastoreType.OPERATIONAL, nodeIid, testVppNode, true); + + writeTransaction.submit(); + + ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction(); + CheckedFuture, ReadFailedException> future = + readOnlyTransaction.read(LogicalDatastoreType.OPERATIONAL, + VppIidFactory.getRendererIID(new RendererKey(VppNodeManager.vppRenderer))); + Optional rendererOptional = future.checkedGet(); + + Assert.assertTrue(rendererOptional.isPresent()); + Assert.assertEquals(1, rendererOptional.get().getRendererNodes().getRendererNode().size()); + Assert.assertEquals(nodeIid, rendererOptional.get().getRendererNodes().getRendererNode().get(0).getNodePath()); + + WriteTransaction writeTransaction2 = dataBroker.newWriteOnlyTransaction(); + Node testVppNode2 = createNode(NODE_NAME, NetconfNodeConnectionStatus.ConnectionStatus.Connecting); + + writeTransaction2.put(LogicalDatastoreType.OPERATIONAL, nodeIid, testVppNode2, true); + + writeTransaction2.submit(); + + ReadOnlyTransaction readOnlyTransaction2 = dataBroker.newReadOnlyTransaction(); + CheckedFuture, ReadFailedException> future2 = + readOnlyTransaction2.read(LogicalDatastoreType.OPERATIONAL, + VppIidFactory.getRendererIID(new RendererKey(VppNodeManager.vppRenderer))); + Optional rendererOptional2 = future2.checkedGet(); + + Assert.assertTrue(rendererOptional2.isPresent()); + Assert.assertEquals(0, rendererOptional2.get().getRendererNodes().getRendererNode().size()); + } + + @After + public void cleanUp() throws Exception { + vppNodeListener.close(); + } +} diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriterTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriterTest.java new file mode 100644 index 000000000..911d2c5ed --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/VppNodeWriterTest.java @@ -0,0 +1,94 @@ +package org.opendaylight.groupbasedpolicy.renderer.vpp.util; + +import com.google.common.util.concurrent.Futures; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InOrder; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Test for {@link VppNodeWriter}. + */ +@RunWith(MockitoJUnitRunner.class) +public class VppNodeWriterTest { + + private static final String RENDERER_NAME = "vpp-renderer"; + + @Mock + private DataBroker dataBroker; + @Mock + private WriteTransaction wTx; + @Captor + private ArgumentCaptor> rendererNodesPathCpt; + @Captor + private ArgumentCaptor rendererNodesCpt; + + private InOrder inOrder; + + private VppNodeWriter nodeWriter; + + @Before + public void setUp() throws Exception { + nodeWriter = new VppNodeWriter(); + Mockito.when(dataBroker.newWriteOnlyTransaction()).thenReturn(wTx); + Mockito.when(wTx.submit()).thenReturn(Futures.immediateCheckedFuture(null)); + } + + @After + public void tearDown() throws Exception { + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testCommitToDatastore_with_node() throws Exception { + final RendererNode node = new RendererNodeBuilder().build(); + nodeWriter.cache(node); + nodeWriter.commitToDatastore(dataBroker); + + commonChecks(); + + final RendererNodes rendererNodes = rendererNodesCpt.getValue(); + Assert.assertEquals(1, rendererNodes.getRendererNode().size()); + } + + @Test + public void testCommitToDatastore_empty() throws Exception { + nodeWriter.commitToDatastore(dataBroker); + + commonChecks(); + + final RendererNodes rendererNodes = rendererNodesCpt.getValue(); + Assert.assertEquals(0, rendererNodes.getRendererNode().size()); + } + + private void commonChecks() { + inOrder = Mockito.inOrder(dataBroker, wTx); + inOrder.verify(dataBroker).newWriteOnlyTransaction(); + inOrder.verify(wTx).merge(Matchers.eq(LogicalDatastoreType.OPERATIONAL), rendererNodesPathCpt.capture(), + rendererNodesCpt.capture(), Matchers.eq(true)); + inOrder.verify(wTx).submit(); + + final InstanceIdentifier rendererNodesPath = rendererNodesPathCpt.getValue(); + Assert.assertEquals(RENDERER_NAME, extractRendererName(rendererNodesPath)); + } + + private String extractRendererName(final InstanceIdentifier rendererNodesPath) { + return rendererNodesPath.firstKeyOf(Renderer.class).getName().getValue(); + } +} -- 2.36.6