ios-xe-renderer policy-manager update 42/39842/15
authorVladimir Lavor <vlavor@cisco.com>
Fri, 3 Jun 2016 13:30:38 +0000 (15:30 +0200)
committerVladimir Lavor <vlavor@cisco.com>
Fri, 17 Jun 2016 10:37:15 +0000 (10:37 +0000)
- create class-map, policy-map, interface
- added chain action
- added UT for NodeManager, PolicyManagerImpl
- util class split to policy-util and sfc-util
- delete case added

Change-Id: Ie11b15cb7b56011f60f7836c11a63ae2e5935562
Signed-off-by: Vladimir Lavor <vlavor@cisco.com>
Signed-off-by: Michal Rehak <mirehak@cisco.com>
16 files changed:
renderers/ios-xe/pom.xml
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/IosXeRendererProviderImpl.java
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/NodeManager.java
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/PolicyManagerImpl.java
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/PolicyMapper.java [deleted file]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/PolicyManagerUtil.java
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/PolicyWriter.java [deleted file]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/ServiceChainingUtil.java [new file with mode: 0644]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/writer/NodeWriter.java [moved from renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/NodeWriter.java with 99% similarity]
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/writer/PolicyWriter.java [new file with mode: 0644]
renderers/ios-xe/src/main/yang/netconf/ietf-inet-types.yang [deleted file]
renderers/ios-xe/src/main/yang/netconf/ned.yang
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/NodeManagerTest.java [new file with mode: 0644]
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/PolicyManagerImplTest.java [new file with mode: 0644]
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/NodeWriterTest.java
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/PolicyManagerUtilTest.java

index ba40c2ecb98c4545f1791bc11cffec2009bd272d..da4bf774ee18d3ca7ce78d6c5cf963f3ddcec480 100755 (executable)
             <groupId>org.opendaylight.netconf</groupId>
             <artifactId>sal-netconf-connector</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-inet-types-2013-07-15</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>1.6.4</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <version>1.6.4</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
index 59acd1498d190518567c8c03a84963438a6e15b3..c1c1eca9cf16c897283c6037e0a30ddcfcfa6ab8 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl;
 
+import com.google.common.base.Preconditions;
 import java.util.List;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
@@ -41,12 +42,10 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 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;
-
 /**
  * Purpose: bootstrap provider implementation of Ios-xe renderer
  */
@@ -58,8 +57,6 @@ public class IosXeRendererProviderImpl implements IosXeRendererProvider, Binding
     private final RendererName rendererName;
     private RendererConfigurationListenerImpl rendererConfigurationListener;
     private IosXeCapableNodeListenerImpl iosXeCapableNodeListener;
-    private PolicyManager policyManager;
-    private NodeManager nodeManager;
 
     public IosXeRendererProviderImpl(final DataBroker dataBroker, final BindingAwareBroker broker,
                                      final RendererName rendererName) {
@@ -86,12 +83,12 @@ public class IosXeRendererProviderImpl implements IosXeRendererProvider, Binding
         LOG.info("starting ios-xe renderer");
         //TODO register listeners:
         // node-manager
-        nodeManager = new NodeManager(dataBroker, providerContext);
+        NodeManager nodeManager = new NodeManager(dataBroker, providerContext);
         // network-topology
         iosXeCapableNodeListener = new IosXeCapableNodeListenerImpl(dataBroker, nodeManager);
 
         // policy-manager and delegates
-        policyManager = new PolicyManagerImpl(dataBroker);
+        PolicyManager policyManager = new PolicyManagerImpl(dataBroker, nodeManager);
         final PolicyManager policyManagerZip = new PolicyManagerZipImpl(policyManager);
 
         // renderer-configuration endpoints
index 3214c5753a876722d082065e8ef0ea880d0af4dd..9916b3446d129f7acaabfeca4e30042fcf2b57a8 100644 (file)
@@ -10,11 +10,16 @@ package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
 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.md.sal.binding.api.ReadWriteTransaction;
+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.ios_xe_provider.impl.util.NodeWriter;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NodeWriter;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 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;
@@ -22,6 +27,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.r
 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.NodeId;
 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;
@@ -32,9 +38,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 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;
@@ -45,7 +49,6 @@ public class NodeManager {
     public static final RendererName iosXeRenderer = new RendererName("ios-xe-renderer");
     private static final TopologyId TOPOLOGY_ID = new TopologyId("topology-netconf");
     private static final Logger LOG = LoggerFactory.getLogger(NodeManager.class);
-    private static final Map<InstanceIdentifier, DataBroker> netconfNodeCache = new HashMap<>();
     private final DataBroker dataBroker;
     private final MountPointService mountService;
     private final List<String> requiredCapabilities;
@@ -56,10 +59,6 @@ public class NodeManager {
         requiredCapabilities = new RequiredCapabilities().initializeRequiredCapabilities();
     }
 
-    static DataBroker getDataBrokerFromCache(InstanceIdentifier iid) {
-        return netconfNodeCache.get(iid); // TODO read from DS
-    }
-
     public void syncNodes(Node dataAfter, Node dataBefore) {
         // New node
         if (dataBefore == null && dataAfter != null) {
@@ -127,14 +126,19 @@ public class NodeManager {
         InstanceIdentifier mountPointIid = getMountpointIid(node);
         // Mountpoint iid == path in renderer-node
         RendererNode rendererNode = remapNode(mountPointIid);
-        DataBroker mountpoint = getNodeMountPoint(mountPointIid);
         NodeWriter nodeWriter = new NodeWriter();
         nodeWriter.cache(rendererNode);
         if (isCapableNetconfDevice(node, netconfNode)) {
+            resolveDisconnectedNode(node);
+            return;
+        }
+        IpAddress managementIpAddress = netconfNode.getHost().getIpAddress();
+        if (managementIpAddress == null) {
+            LOG.warn("Node {} does not contain management ip address", node.getNodeId().getValue());
+            resolveDisconnectedNode(node);
             return;
         }
         nodeWriter.commitToDatastore(dataBroker);
-        netconfNodeCache.put(mountPointIid, mountpoint);
     }
 
     private void resolveDisconnectedNode(Node node) {
@@ -143,7 +147,6 @@ public class NodeManager {
         NodeWriter nodeWriter = new NodeWriter();
         nodeWriter.cache(rendererNode);
         nodeWriter.removeFromDatastore(dataBroker);
-        netconfNodeCache.remove(mountPointIid);
     }
 
     private RendererNode remapNode(InstanceIdentifier path) {
@@ -183,7 +186,10 @@ public class NodeManager {
         return true;
     }
 
-    private DataBroker getNodeMountPoint(InstanceIdentifier mountPointIid) {
+    DataBroker getNodeMountPoint(InstanceIdentifier mountPointIid) {
+        if (mountPointIid == null) {
+            return null;
+        }
         Optional<MountPoint> optionalObject = mountService.getMountPoint(mountPointIid);
         MountPoint mountPoint;
         if (optionalObject.isPresent()) {
@@ -202,6 +208,44 @@ public class NodeManager {
         return null;
     }
 
+    NodeId getNodeIdByMountpointIid(InstanceIdentifier mountpointIid) {
+        NodeKey identifier = (NodeKey) mountpointIid.firstKeyOf(Node.class);
+        return identifier.getNodeId();
+    }
+
+    String getNodeManagementIpByMountPointIid(InstanceIdentifier mountpointIid) {
+        NodeId nodeId = getNodeIdByMountpointIid(mountpointIid);
+        InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(new TopologyId(NodeManager.TOPOLOGY_ID)))
+                .child(Node.class, new NodeKey(nodeId)).build();
+        ReadWriteTransaction rwt = dataBroker.newReadWriteTransaction();
+        try {
+            CheckedFuture<Optional<Node>, ReadFailedException> submitFuture =
+                    rwt.read(LogicalDatastoreType.CONFIGURATION, nodeIid);
+            Optional<Node> optional = submitFuture.checkedGet();
+            if (optional != null && optional.isPresent()) {
+                Node node = optional.get();
+                if (node != null) {
+                    NetconfNode netconfNode = getNodeAugmentation(node);
+                    if (netconfNode != null && netconfNode.getHost() != null) {
+                        IpAddress ipAddress = netconfNode.getHost().getIpAddress();
+                        if (ipAddress != null && ipAddress.getIpv4Address() != null) {
+                            return ipAddress.getIpv4Address().getValue();
+                        }
+                        return null;
+                    }
+                }
+            } else {
+                LOG.debug("Failed to read. {}", Thread.currentThread().getStackTrace()[1]);
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Read transaction failed to {} ", e);
+        } catch (Exception e) {
+            LOG.error("Failed to .. {}", e.getMessage());
+        }
+        return null;
+    }
+
     private NetconfNode getNodeAugmentation(Node node) {
         NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
         if (netconfNode == null) {
@@ -228,9 +272,8 @@ public class NodeManager {
          * @return list of string representations of required capabilities
          */
         List<String> initializeRequiredCapabilities() {
-            String writableDataStore = "urn:ietf:params:netconf:capability:writable-running:1.0";
             String capabilityEntries[] = {ned, tailfCommon, tailfCliExtension, tailfMetaExtension, ietfYangTypes,
-                    ietfInetTypes, writableDataStore};
+                    ietfInetTypes};
             return Arrays.asList(capabilityEntries);
         }
     }
index d22205825fde400fda327230ca605ad8c5719178..18988617cce56a3742d47067d16220ee215ce482 100644 (file)
 
 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager;
 
-import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.In;
-import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.Out;
-import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.CONSUMER;
-import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.PROVIDER;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
-import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.manager.PolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
-import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyWriter;
-import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.RendererPolicyUtil;
-import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.LocalBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.service.type.choice.ServiceFunctionForwarderBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308.config.service.chain.grouping.IpBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.AddressEndpointKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.rule.group.with.renderer.endpoint.participation.RuleGroupWithRendererEndpointParticipation;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicy;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroup;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.AddressEndpointWithLocationAug;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.DsAction.Create;
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.DsAction.Delete;
 
 public class PolicyManagerImpl implements PolicyManager {
 
-    private static final Logger LOG = LoggerFactory.getLogger(PolicyMapper.class);
+    private static final Logger LOG = LoggerFactory.getLogger(PolicyManagerImpl.class);
+    private static final String policyMapName = "service-chains";
     private final DataBroker dataBroker;
-    private final PolicyMapper mapper;
-    private final String policyMapName = "service-chains";
-    private Map<DataBroker, PolicyWriter> perDeviceWriterCache = new HashMap<>();
+    private final NodeManager nodeManager;
 
-    public enum ActionCase { ALLOW, CHAIN }
-
-
-    public PolicyManagerImpl(final DataBroker dataBroker) {
+    public PolicyManagerImpl(final DataBroker dataBroker,
+                             final NodeManager nodeManager) {
         this.dataBroker = Preconditions.checkNotNull(dataBroker);
-        mapper = new PolicyMapper(dataBroker);
+        this.nodeManager = Preconditions.checkNotNull(nodeManager);
     }
 
     @Override
-    public ListenableFuture<Boolean> syncPolicy(final Configuration dataBefore, final Configuration dataAfter) {
-        // CREATE
+    public ListenableFuture<Boolean> syncPolicy(final Configuration dataAfter, final Configuration dataBefore) {
+        if (dataBefore == null && dataAfter != null) {
+            return createPolicy(dataAfter);
+        }
+        if (dataBefore != null && dataAfter != null) {
+            return updatePolicy(dataAfter, dataBefore);
+        }
+        if (dataBefore != null) {
+            return deletePolicy(dataBefore);
+        }
+        return Futures.immediateFuture(false);
+    }
+
+    private ListenableFuture<Boolean> syncPolicy(final Configuration dataAfter, DsAction action) {
+        if (dataAfter.getRendererEndpoints() == null
+                || dataAfter.getRendererEndpoints().getRendererEndpoint() == null) {
+            LOG.debug("no configuration obtained - skipping");
+            return Futures.immediateFuture(true);
+        }
+        final Map<DataBroker, PolicyWriter> policyWriterPerDeviceCache = new HashMap<>();
         for (RendererEndpoint rendererEndpoint : dataAfter.getRendererEndpoints().getRendererEndpoint()) {
-            // Get mountpoint
-            if (dataAfter.getEndpoints() == null) {
+            if (dataAfter.getEndpoints() == null || dataAfter.getEndpoints().getAddressEndpointWithLocation() == null) {
+                LOG.debug("renderer-endpoint: missing address-endpoint-with-location");
                 continue;
             }
-            DataBroker mountpoint = getAbsoluteLocationMountpoint(rendererEndpoint, dataAfter.getEndpoints()
-                    .getAddressEndpointWithLocation());
+            final List<AddressEndpointWithLocation> endpointsWithLocation = dataAfter.getEndpoints()
+                    .getAddressEndpointWithLocation();
+            final InstanceIdentifier mountpointIid = PolicyManagerUtil.getAbsoluteLocationMountpoint(rendererEndpoint, endpointsWithLocation);
+            final DataBroker mountpoint = nodeManager.getNodeMountPoint(mountpointIid);
             if (mountpoint == null) {
+                LOG.debug("no data-broker for mount-point [{}] available", mountpointIid);
                 continue;
             }
-            // Initialize appropriate writer
-            PolicyWriter policyWriter;
-            if (perDeviceWriterCache.containsKey(mountpoint)) {
-                policyWriter = perDeviceWriterCache.get(mountpoint);
-            } else {
-                policyWriter = new PolicyWriter(mountpoint);
-                perDeviceWriterCache.put(mountpoint, policyWriter);
+            // Find policy writer
+            PolicyWriter policyWriter = policyWriterPerDeviceCache.get(mountpoint);
+            if (policyWriter == null) {
+                // Initialize new policy writer
+                final String interfaceName = PolicyManagerUtil.getInterfaceNameForPolicyMap(rendererEndpoint, endpointsWithLocation);
+                final NodeId nodeId = nodeManager.getNodeIdByMountpointIid(mountpointIid);
+                final String managementIpAddress = nodeManager.getNodeManagementIpByMountPointIid(mountpointIid);
+                if (interfaceName == null || managementIpAddress == null) {
+                    LOG.debug("can not create policyWriter: interface={}, managementIpAddress={}",
+                            interfaceName, managementIpAddress);
+                    continue;
+                }
+                policyWriter = new PolicyWriter(mountpoint, interfaceName, managementIpAddress, policyMapName, nodeId);
+                policyWriterPerDeviceCache.put(mountpoint, policyWriter);
             }
+
+            final Sgt sourceSgt = PolicyManagerUtil.findSgtTag(rendererEndpoint, dataAfter.getEndpoints()
+                    .getAddressEndpointWithLocation());
             // Peer Endpoint
             for (PeerEndpointWithPolicy peerEndpoint : rendererEndpoint.getPeerEndpointWithPolicy()) {
-                // Sgt Tags
-                final Sgt sourceSgt = findSgtTag(rendererEndpoint, dataAfter.getEndpoints()
-                        .getAddressEndpointWithLocation());
-                final Sgt destinationSgt = findSgtTag(peerEndpoint, dataAfter.getEndpoints()
+                final Sgt destinationSgt = PolicyManagerUtil.findSgtTag(peerEndpoint, dataAfter.getEndpoints()
                         .getAddressEndpointWithLocation());
                 if (sourceSgt == null || destinationSgt == null) {
+                    LOG.debug("endpoint-policy: missing sgt value(sourceSgt={}, destinationSgt={})",
+                            sourceSgt, destinationSgt);
                     continue;
                 }
-                syncPolicyEntities(sourceSgt, destinationSgt, policyWriter, dataAfter, peerEndpoint);
+                PolicyManagerUtil.syncPolicyEntities(sourceSgt, destinationSgt, policyWriter, dataAfter, peerEndpoint);
             }
         }
-        // Flush
-        perDeviceWriterCache.values().forEach(PolicyWriter::commitToDatastore);
-        perDeviceWriterCache.clear();
-
-        return Futures.immediateFuture(true);
-    }
-
-    private void syncPolicyEntities(final Sgt sourceSgt, final Sgt destinationSgt, PolicyWriter policyWriter,
-                                   final Configuration dataAfter, final PeerEndpointWithPolicy peerEndpoint) {
-        // Class map
-        String classMapName = generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
-        Match match = mapper.createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
-        ClassMap classMap = mapper.createClassMap(classMapName, match);
-        policyWriter.write(classMap);
-
-        Map<ActionCase, Action> actionMap = getActionInDirection(dataAfter, peerEndpoint);
-        if (actionMap == null || actionMap.isEmpty()) {
-            return;
-        }
-        // Policy map entry
-        List<Class> policyMapEntries = new ArrayList<>();
-        if (actionMap.containsKey(ActionCase.ALLOW)) {
-            policyMapEntries = resolveAllowAction();
+        if (action.equals(Create)) {
+            policyWriterPerDeviceCache.values().forEach(PolicyWriter::commitToDatastore);
+            return Futures.immediateFuture(true);
+        } else if (action.equals(Delete)) {
+            policyWriterPerDeviceCache.values().forEach(PolicyWriter::removeFromDatastore);
+            return Futures.immediateFuture(true);
         }
-        if (actionMap.containsKey(ActionCase.CHAIN)) {
-            policyMapEntries = resolveChainAction(peerEndpoint, sourceSgt, destinationSgt, actionMap, classMapName);
-        }
-        policyWriter.write(policyMapEntries);
+        return Futures.immediateFuture(false);
     }
 
-    private Sgt findSgtTag(final AddressEndpointKey endpointKey,
-                            final List<AddressEndpointWithLocation> endpointsWithLocation) {
-        if (endpointKey == null || endpointsWithLocation == null) {
-            return null;
-        }
-        AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpointKey,
-                endpointsWithLocation);
-        AddressEndpointWithLocationAug augmentation = endpointWithLocation.getAugmentation(AddressEndpointWithLocationAug.class);
-        if (augmentation == null) {
-            return null;
-        }
-
-        return augmentation.getSgt();
+    private ListenableFuture<Boolean> createPolicy(Configuration data) {
+        return syncPolicy(data, Create);
     }
 
-    private List<Class> resolveChainAction(final PeerEndpointWithPolicy peerEndpoint, final Sgt sourceSgt,
-                                           final Sgt destinationSgt, final Map<ActionCase, Action> actionMap,
-                                           final String classMapName) {
-        List<Class> entries = new ArrayList<>();
-        final Action action = actionMap.get(ActionCase.CHAIN);
-        ServiceFunctionPath servicePath = PolicyManagerUtil.getServicePath(action.getParameterValue());
-        if (servicePath == null) {
-            return null;
-        }
-        TenantId tenantId = getTenantId(peerEndpoint);
-        if (tenantId == null) {
-            return  null;
-        }
-        RenderedServicePath renderedPath = PolicyManagerUtil.createRenderedPath(servicePath, tenantId);
-        entries.add(mapper.createPolicyEntry(classMapName, renderedPath, ActionCase.CHAIN));
-        if (servicePath.isSymmetric()) {
-            // symmetric path is in opposite direction. Roles of renderer and peer endpoint will invert
-            RenderedServicePath symmetricPath = PolicyManagerUtil
-                    .createSymmetricRenderedPath(servicePath, renderedPath, tenantId);
-            String oppositeClassMapName = generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
-            entries.add(mapper.createPolicyEntry(oppositeClassMapName, symmetricPath, ActionCase.CHAIN));
-        }
-        return entries;
-    }
-
-    private List<Class> resolveAllowAction() {
-        List<Class> entries = new ArrayList<>();
-        entries.add(mapper.createPolicyEntry(policyMapName, null, ActionCase.ALLOW));
-        return entries;
+    private ListenableFuture<Boolean> deletePolicy(Configuration data) {
+        return syncPolicy(data, Delete);
     }
 
-    private DataBroker getAbsoluteLocationMountpoint(final RendererEndpoint endpoint,
-                                                     final List<AddressEndpointWithLocation> endpointsWithLocation) {
-        if (endpoint == null || endpointsWithLocation == null) {
-            return null;
-        }
-        AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpoint,
-                endpointsWithLocation);
-        final AbsoluteLocation absoluteLocation = endpointWithLocation.getAbsoluteLocation();
-        final LocationType locationType = absoluteLocation.getLocationType();
-        ExternalLocationCase location = (ExternalLocationCase) locationType;
-        if (location == null) {
-            LOG.warn("Endpoint {} does not contain info about external location",
-                    endpointWithLocation.getKey().toString());
-            return null;
-        }
-        InstanceIdentifier mountPointId = location.getExternalNodeMountPoint();
-        return NodeManager.getDataBrokerFromCache(mountPointId);
-    }
-
-    private String generateClassMapName(Integer sourceTag, Integer destinationTag) {
-        return "srcTag" + sourceTag + "_dstTag" + destinationTag;
-    }
-
-    private Map<ActionCase, Action> getActionInDirection(Configuration data, PeerEndpointWithPolicy peer) {
-        List<ResolvedRule> rulesInDirection = new ArrayList<>();
-        // Find all rules in desired direction
-        for (RuleGroupWithRendererEndpointParticipation ruleGroupKey :
-                peer.getRuleGroupWithRendererEndpointParticipation()) {
-            EndpointPolicyParticipation participation = ruleGroupKey.getRendererEndpointParticipation();
-            RuleGroup ruleGroup = findRuleGroup(data, ruleGroupKey);
-            if (ruleGroup == null || ruleGroup.getResolvedRule() == null) {
-                continue;
-            }
-
-            for (ResolvedRule resolvedRule : ruleGroup.getResolvedRule()) {
-                if (resolvedRule == null) {
-                    continue;
-                }
-                if (resolvedRule.getClassifier() == null || resolvedRule.getAction() == null) {
-                    continue;
-                }
-                // TODO only first Classifier used
-                Classifier classifier = resolvedRule.getClassifier().get(0);
-                HasDirection.Direction direction = classifier.getDirection();
-                if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
-                        (participation.equals(CONSUMER) && direction.equals(In))) {
-                    rulesInDirection.add(resolvedRule);
-                }
-            }
-        }
-        if (rulesInDirection.isEmpty()) {
-            return null; // TODO define drop?
-        }
-        // TODO use only first rule with ActionDefinitionID for now
-        Map<ActionCase, Action> result = new HashMap<>();
-        for (ResolvedRule resolvedRule : rulesInDirection) {
-            // TODO only first action used for now
-            Action action = resolvedRule.getAction().get(0);
-            if (action.getActionDefinitionId() != null) {
-                ActionDefinitionId actionDefinitionId = action.getActionDefinitionId();
-                if (actionDefinitionId.equals(AllowActionDefinition.ID)) {
-                    result.put(ActionCase.ALLOW, action);
-                    return result;
-                } else if (actionDefinitionId.equals(ChainActionDefinition.ID)) {
-                    result.put(ActionCase.CHAIN, action);
-                    return result;
-                }
-            }
-        }
-        return null;
-    }
-
-    private RuleGroup findRuleGroup(final Configuration data,
-                                    final RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation) {
-        final TenantId tenantId = ruleGroupWithParticipation.getTenantId();
-        final ContractId contractId = ruleGroupWithParticipation.getContractId();
-        final SubjectName subjectName = ruleGroupWithParticipation.getSubjectName();
-        for (RuleGroup ruleGroup : data.getRuleGroups().getRuleGroup()) {
-            if (!ruleGroup.getTenantId().equals(tenantId))
-                continue;
-            if (!ruleGroup.getContractId().equals(contractId)) {
-                continue;
-            }
-            if (ruleGroup.getSubjectName().equals(subjectName)) {
-                return ruleGroup;
-            }
-        }
+    private ListenableFuture<Boolean> updatePolicy(Configuration dataAfter, Configuration dataBefore) {
+        // TODO implement
         return null;
     }
 
-    private TenantId getTenantId(PeerEndpointWithPolicy peer) {
-        for (RuleGroupWithRendererEndpointParticipation ruleGroup :
-                peer.getRuleGroupWithRendererEndpointParticipation()) {
-            if (ruleGroup.getTenantId() != null) {
-                return ruleGroup.getTenantId();
-            }
-        }
-        return null;
-    }
-
-
-    private void resolveFirstSffOnClassifier(final Ipv4Address nodeIpAddress,
-                                             final Set<RenderedServicePath> firstHops) {
-        // Local forwarder
-        LocalBuilder localSffBuilder = new LocalBuilder();
-        localSffBuilder.setIp(new IpBuilder().setAddress(nodeIpAddress).build());
-
-        // TODO add sff to writer
-
-        for (RenderedServicePath renderedPath : firstHops) {
-            // Remote forwarder
-            RenderedServicePathHop firstRenderedPathHop = renderedPath.getRenderedServicePathHop().get(0);
-            SffName sffName = firstRenderedPathHop.getServiceFunctionForwarder();
-
-            // Remap sff and its management ip address
-            org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder serviceFunctionForwarder =
-                    SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName);
-            String sffMgmtIpAddress = serviceFunctionForwarder.getIpMgmtAddress().getIpv4Address().getValue();
-
-            ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
-            remoteSffBuilder.setName(sffName.getValue())
-                    .setKey(new ServiceFfNameKey(sffName.getValue()))
-                    .setIp(new IpBuilder().setAddress(new Ipv4Address(sffMgmtIpAddress)).build());
-            // TODO add sff to writer
-
-            // Service chain
-            List<Services> services = new ArrayList<>();
-            ServiceTypeChoice serviceTypeChoice = sffTypeChoice(sffName.getValue());
-            ServicesBuilder servicesBuilder = new ServicesBuilder();
-            servicesBuilder.setServiceIndexId(renderedPath.getStartingIndex())
-                    .setServiceTypeChoice(serviceTypeChoice);
-            List<ServicePath> servicePaths = new ArrayList<>();
-            ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
-            servicePathBuilder.setKey(new ServicePathKey(renderedPath.getPathId()))
-                    .setServicePathId(renderedPath.getPathId())
-                    .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
-                            .setServiceIndex(new ServiceIndexBuilder()
-                                    .setServices(services).build()).build());
-            servicePaths.add(servicePathBuilder.build());
-            ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
-            chainBuilder.setServicePath(servicePaths);
-            ServiceChain serviceChain = chainBuilder.build();
-            // TODO add service-chain to writer
-        }
-    }
-
-    private ServiceTypeChoice sffTypeChoice(String forwarderName) {
-        ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
-        sffBuilder.setServiceFunctionForwarder(forwarderName);
-        return sffBuilder.build();
-    }
-
     @Override
     public void close() {
         //NOOP
     }
+
+    enum DsAction {Create, Delete}
+
+    public enum ActionCase {ALLOW, CHAIN}
 }
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/PolicyMapper.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/PolicyMapper.java
deleted file mode 100644 (file)
index 917d9d0..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.ios_xe_provider.impl.manager;
-
-import com.google.common.base.Preconditions;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308.ClassNameType;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308.PolicyActionType;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.SecurityGroupBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.Destination;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.DestinationBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.Source;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.SourceBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.Type;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.TypeBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMapBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMapKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMap;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMapBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMapKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.ClassBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.ClassKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.ActionList;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.ActionListBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.ActionListKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.ForwardCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.ForwardBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.forward.ServicePath;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.forward.ServicePathBuilder;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.forward.ServicePathKey;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.ActionCase.CHAIN;
-
-class PolicyMapper {
-
-    private final DataBroker dataBroker;
-    private static final Logger LOG = LoggerFactory.getLogger(PolicyMapper.class);
-
-    PolicyMapper(final DataBroker dataBroker) {
-        this.dataBroker = Preconditions.checkNotNull(dataBroker);
-    }
-
-    Match createSecurityGroupMatch(int sourceTag, int destinationTag) {
-        MatchBuilder matchBuilder = new MatchBuilder();
-        SecurityGroupBuilder sgBuilder = new SecurityGroupBuilder();
-        Source source = new SourceBuilder().setTag(sourceTag).build();
-        Destination destination = new DestinationBuilder().setTag(destinationTag).build();
-        sgBuilder.setSource(source)
-                .setDestination(destination);
-        return matchBuilder.setSecurityGroup(sgBuilder.build()).build();
-    }
-
-    ClassMap createClassMap(final String classMapName, Match match) {
-        ClassMapBuilder cmBuilder = new ClassMapBuilder();
-        cmBuilder.setName(classMapName)
-                .setKey(new ClassMapKey(classMapName))
-                .setMatch(match)
-                .setPrematch(ClassMap.Prematch.MatchAll);
-        return cmBuilder.build();
-    }
-
-    Class createPolicyEntry(String policyClassName, RenderedServicePath renderedPath,
-                            PolicyManagerImpl.ActionCase actionCase) {
-        // Forward Case
-        ForwardCaseBuilder forwardCaseBuilder = new ForwardCaseBuilder();
-        if (actionCase.equals(CHAIN) && renderedPath != null) {
-            // Chain Action
-            ForwardBuilder forwardBuilder = new ForwardBuilder();
-            List<ServicePath> servicePaths = new ArrayList<>();
-            ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
-            servicePathBuilder.setKey(new ServicePathKey(renderedPath.getPathId()))
-                    .setServicePathId(renderedPath.getPathId())
-                    .setServiceIndex(renderedPath.getStartingIndex());
-            servicePaths.add(servicePathBuilder.build());
-            forwardBuilder.setServicePath(servicePaths);
-            forwardCaseBuilder.setForward(forwardBuilder.build());
-        }
-        // Create Action List
-        List<ActionList> actionList = new ArrayList<>();
-        ActionListBuilder actionListBuilder = new ActionListBuilder();
-        actionListBuilder.setKey(new ActionListKey(PolicyActionType.Forward))
-                .setActionType(PolicyActionType.Forward)
-                .setActionParam(forwardCaseBuilder.build());
-        actionList.add(actionListBuilder.build());
-        // Build class entry
-        ClassBuilder policyClassBuilder = new ClassBuilder();
-        policyClassBuilder.setName(new ClassNameType(policyClassName))
-                .setKey(new ClassKey(new ClassNameType(policyClassName)))
-                .setActionList(actionList);
-        return policyClassBuilder.build();
-    }
-
-    public Type getServicePolicyType(String name) {
-        TypeBuilder typeBuilder = new TypeBuilder();
-        org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.type.ServiceChainBuilder serviceChainBuilder =
-                new org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.type.ServiceChainBuilder();
-        serviceChainBuilder.setName(name)
-                .setDirection(org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.type.ServiceChain.Direction.Input);
-        typeBuilder.setServiceChain(serviceChainBuilder.build());
-        return typeBuilder.build();
-    }
-
-    PolicyMap policyMap(String policyMapName) {
-        PolicyMapBuilder pmBuilder = new PolicyMapBuilder();
-        pmBuilder.setName(policyMapName)
-                .setKey(new PolicyMapKey(policyMapName))
-                .setType(null);
-        return pmBuilder.build();
-    }
-}
index 85b7737b1062d1dd06f1be02329faad665953fa4..033034d53196c52040a306afab53382f8883d444 100644 (file)
 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util;
 
 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
-import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
-import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriter;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
-import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308.ClassNameType;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308.PolicyActionType;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.SecurityGroup;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.SecurityGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.Destination;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.DestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.Source;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._class.map.match.grouping.security.group.SourceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.ServicePolicy;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.ServicePolicyBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.TypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.type.ServiceChain;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.type.ServiceChainBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMapKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMap;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMapKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.Match;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._class.map.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.ClassBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.ClassKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.ActionList;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.ActionListBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.ActionListKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.AppnavPolicyBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.ForwardCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.ForwardBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.forward.ServicePath;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.forward.ServicePathBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map._class.action.list.action.param.forward._case.forward.ServicePathKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.AddressEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.rule.group.with.renderer.endpoint.participation.RuleGroupWithRendererEndpointParticipation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.AddressEndpointWithLocationAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.ActionCase.CHAIN;
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.In;
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.Out;
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.CONSUMER;
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.PROVIDER;
+
 public class PolicyManagerUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(PolicyManagerUtil.class);
 
-    public static ServiceFunctionPath getServicePath(List<ParameterValue> params) {
-        if (params == null || params.isEmpty()) {
-            LOG.error("Cannot found service path, parameter value is null");
+    public static void syncPolicyEntities(final Sgt sourceSgt, final Sgt destinationSgt, PolicyWriter policyWriter,
+                                          final Configuration dataAfter, final PeerEndpointWithPolicy peerEndpoint) {
+        // Class map
+        final String classMapName = PolicyManagerUtil.generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
+        final Match match = PolicyManagerUtil.createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
+        final ClassMap classMap = PolicyManagerUtil.createClassMap(classMapName, match);
+        final Map<PolicyManagerImpl.ActionCase, Action> actionMap = PolicyManagerUtil.getActionInDirection(dataAfter, peerEndpoint);
+        if (actionMap == null || actionMap.isEmpty()) {
+            return;
+        }
+        policyWriter.cache(classMap);
+
+        // Policy map entry
+        if (actionMap.containsKey(PolicyManagerImpl.ActionCase.CHAIN)) {
+            ServiceChainingUtil.resolveChainAction(peerEndpoint, sourceSgt, destinationSgt, actionMap, classMapName, policyWriter);
+        }
+    }
+
+    public static Sgt findSgtTag(final AddressEndpointKey endpointKey,
+                                 final List<AddressEndpointWithLocation> endpointsWithLocation) {
+        if (endpointKey == null || endpointsWithLocation == null) {
             return null;
         }
-        Map<String, Object> paramsMap = new HashMap<>();
-        for (ParameterValue value : params) {
-            if (value.getName() == null)
-                continue;
-            if (value.getIntValue() != null) {
-                paramsMap.put(value.getName().getValue(), value.getIntValue());
-            } else if (value.getStringValue() != null) {
-                paramsMap.put(value.getName().getValue(), value.getStringValue());
-            }
+        final AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpointKey,
+                endpointsWithLocation);
+        final AddressEndpointWithLocationAug augmentation = endpointWithLocation.getAugmentation(AddressEndpointWithLocationAug.class);
+        if (augmentation == null) {
+            return null;
         }
-        String chainName = null;
-        for (String name : paramsMap.keySet()) {
-            if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
-                chainName = (String) paramsMap.get(name);
+
+        return augmentation.getSgt();
+    }
+
+    private static Match createSecurityGroupMatch(final int sourceTag, final int destinationTag) {
+        final SecurityGroupBuilder sgBuilder = new SecurityGroupBuilder();
+        final Source source = new SourceBuilder().setTag(sourceTag).build();
+        final Destination destination = new DestinationBuilder().setTag(destinationTag).build();
+        sgBuilder.setDestination(destination)
+                .setSource(source);
+        final SecurityGroup securityGroup = sgBuilder.build();
+        final MatchBuilder matchBuilder = new MatchBuilder();
+        matchBuilder.setSecurityGroup(securityGroup);
+        return matchBuilder.build();
+    }
+
+    static ClassMap createClassMap(final String classMapName, final Match match) {
+        final ClassMapBuilder cmBuilder = new ClassMapBuilder();
+        cmBuilder.setName(classMapName)
+                .setKey(new ClassMapKey(classMapName))
+                .setPrematch(ClassMap.Prematch.MatchAll)
+                .setMatch(match);
+        return cmBuilder.build();
+    }
+
+    static TenantId getTenantId(final PeerEndpointWithPolicy peer) {
+        for (RuleGroupWithRendererEndpointParticipation ruleGroup :
+                peer.getRuleGroupWithRendererEndpointParticipation()) {
+            if (ruleGroup.getTenantId() != null) {
+                return ruleGroup.getTenantId();
             }
         }
-        if (chainName == null) {
-            LOG.error("Cannot found service path, chain name is null");
+        return null;
+    }
+
+    static String generateClassMapName(final int sourceTag, final int destinationTag) {
+        return "srcTag" + sourceTag + "_dstTag" + destinationTag;
+    }
+
+    static Class createPolicyEntry(final String policyClassName, final RenderedServicePath renderedPath,
+                                   final PolicyManagerImpl.ActionCase actionCase) {
+        // Forward Case
+        final ForwardCaseBuilder forwardCaseBuilder = new ForwardCaseBuilder();
+        if (actionCase.equals(CHAIN) && renderedPath != null) {
+            // Chain Action
+            final ForwardBuilder forwardBuilder = new ForwardBuilder();
+            final List<ServicePath> servicePaths = new ArrayList<>();
+            final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
+            servicePathBuilder.setKey(new ServicePathKey(renderedPath.getPathId()))
+                    .setServicePathId(renderedPath.getPathId())
+                    .setServiceIndex(renderedPath.getStartingIndex());
+            servicePaths.add(servicePathBuilder.build());
+            forwardBuilder.setServicePath(servicePaths);
+            forwardCaseBuilder.setForward(forwardBuilder.build());
+        }
+        // Create Action List
+        final List<ActionList> actionList = new ArrayList<>();
+        final ActionListBuilder actionListBuilder = new ActionListBuilder();
+        actionListBuilder.setKey(new ActionListKey(PolicyActionType.Forward))
+                .setActionType(PolicyActionType.Forward)
+                .setActionParam(forwardCaseBuilder.build());
+        actionList.add(actionListBuilder.build());
+        // Build class entry
+        final ClassBuilder policyClassBuilder = new ClassBuilder();
+        policyClassBuilder.setName(new ClassNameType(policyClassName))
+                .setKey(new ClassKey(new ClassNameType(policyClassName)))
+                .setActionList(actionList);
+        return policyClassBuilder.build();
+    }
+
+    public static PolicyMap createPolicyMap(final String policyMapName, final List<Class> policyMapEntries) {
+        // Create default class entry
+        final AppnavPolicyBuilder appnavPolicyBuilder = new AppnavPolicyBuilder();
+        appnavPolicyBuilder.setPassThrough(true);
+        final ClassBuilder defaultBuilder = new ClassBuilder();
+        defaultBuilder.setName(new ClassNameType("class-default"))
+                .setKey(new ClassKey(new ClassNameType("class-default")))
+                .setAppnavPolicy(appnavPolicyBuilder.build());
+        policyMapEntries.add(defaultBuilder.build());
+        // Construct policy map
+        final PolicyMapBuilder policyMapBuilder = new PolicyMapBuilder();
+        policyMapBuilder.setName(policyMapName)
+                .setKey(new PolicyMapKey(policyMapName))
+                .setType(PolicyMap.Type.ServiceChain)
+                .setXmlClass(policyMapEntries);
+        return policyMapBuilder.build();
+    }
+
+    public static ServicePolicy createServicePolicy(final String chainName, final ServiceChain.Direction direction) {
+        // Service Chain
+        final ServiceChainBuilder serviceChainBuilder = new ServiceChainBuilder();
+        serviceChainBuilder.setName(chainName) // Same as the policy map name
+                .setDirection(direction);
+        // Service policy
+        final TypeBuilder typeBuilder = new TypeBuilder();
+        typeBuilder.setServiceChain(serviceChainBuilder.build());
+        // Service Policy
+        ServicePolicyBuilder servicePolicyBuilder = new ServicePolicyBuilder();
+        servicePolicyBuilder.setType(typeBuilder.build());
+
+        return servicePolicyBuilder.build();
+    }
+
+    public static InstanceIdentifier getAbsoluteLocationMountpoint(final RendererEndpoint endpoint,
+                                                                   final List<AddressEndpointWithLocation> endpointsWithLocation) {
+        if (endpointsWithLocation.isEmpty()) {
             return null;
         }
-        ServiceFunctionPath serviceFunctionPath = findServiceFunctionPath(new SfcName(chainName));
-        if (serviceFunctionPath == null) {
-            LOG.error("Service function path not found for name {}", chainName);
+        AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpoint,
+                endpointsWithLocation);
+        final AbsoluteLocation absoluteLocation = endpointWithLocation.getAbsoluteLocation();
+        final LocationType locationType = absoluteLocation.getLocationType();
+        ExternalLocationCase location = (ExternalLocationCase) locationType;
+        if (location == null) {
+            LOG.warn("Endpoint {} does not contain info about external location",
+                    endpointWithLocation.getKey().toString());
             return null;
         }
-        return serviceFunctionPath;
+        return location.getExternalNodeMountPoint();
     }
 
-    public static RenderedServicePath createRenderedPath(ServiceFunctionPath sfp, TenantId tenantId) {
-        RenderedServicePath renderedServicePath;
-        // Try to read existing RSP
-        RspName rspName = new RspName(sfp.getName().getValue() + tenantId.getValue() + "-gbp-rsp");
-        renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
-        if (renderedServicePath != null) {
-            return renderedServicePath;
+    public static String getInterfaceNameForPolicyMap(final RendererEndpoint endpoint,
+                                                      final List<AddressEndpointWithLocation> endpointsWithLocation) {
+        if (endpoint == null || endpointsWithLocation == null) {
+            return null;
+        }
+        final AddressEndpointWithLocation endpointWithLocation = RendererPolicyUtil.lookupEndpoint(endpoint,
+                endpointsWithLocation);
+        final AbsoluteLocation absoluteLocation = endpointWithLocation.getAbsoluteLocation();
+        final LocationType locationType = absoluteLocation.getLocationType();
+        final ExternalLocationCase location = (ExternalLocationCase) locationType;
+        if (location == null) {
+            LOG.warn("Endpoint {} does not contain info about external location",
+                    endpointWithLocation.getKey().toString());
+            return null;
         }
-        LOG.info("Rendered service path with name {} not found, creating a new one ..", rspName.getValue());
-        CreateRenderedPathInput input = new CreateRenderedPathInputBuilder()
-                .setParentServiceFunctionPath(sfp.getName().getValue())
-                .setName(rspName.getValue())
-                .setSymmetric(sfp.isSymmetric())
-                .build();
-        renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, input);
-        LOG.info("Rendered service path {} created", rspName.getValue());
-        return renderedServicePath;
+        return location.getExternalNodeConnector();
     }
 
-    private static ServiceFunctionPath findServiceFunctionPath(SfcName chainName) {
-        ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
-        for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
-            if (serviceFunctionPath.getServiceChainName().equals(chainName)) {
-                return serviceFunctionPath;
+
+    private static Map<PolicyManagerImpl.ActionCase, Action> getActionInDirection(final Configuration data, final PeerEndpointWithPolicy peer) {
+        final List<ResolvedRule> rulesInDirection = new ArrayList<>();
+        // Find all rules in desired direction
+        for (RuleGroupWithRendererEndpointParticipation ruleGroupKey :
+                peer.getRuleGroupWithRendererEndpointParticipation()) {
+            final EndpointPolicyParticipation participation = ruleGroupKey.getRendererEndpointParticipation();
+            final RuleGroup ruleGroup = findRuleGroup(data, ruleGroupKey);
+            if (ruleGroup == null || ruleGroup.getResolvedRule() == null) {
+                continue;
+            }
+
+            for (ResolvedRule resolvedRule : ruleGroup.getResolvedRule()) {
+                if (resolvedRule == null) {
+                    continue;
+                }
+                if (resolvedRule.getClassifier() == null || resolvedRule.getAction() == null) {
+                    continue;
+                }
+                // TODO only first Classifier used
+                final Classifier classifier = resolvedRule.getClassifier().get(0);
+                final HasDirection.Direction direction = classifier.getDirection();
+                if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
+                        (participation.equals(CONSUMER) && direction.equals(In))) {
+                    rulesInDirection.add(resolvedRule);
+                }
+            }
+        }
+        if (rulesInDirection.isEmpty()) {
+            return null;
+        }
+        // TODO use only first rule with ActionDefinitionID for now
+        final Map<PolicyManagerImpl.ActionCase, Action> result = new HashMap<>();
+        for (ResolvedRule resolvedRule : rulesInDirection) {
+            // TODO only first action used for now
+            final Action action = resolvedRule.getAction().get(0);
+            if (action.getActionDefinitionId() != null) {
+                final ActionDefinitionId actionDefinitionId = action.getActionDefinitionId();
+                // Currently only chain action is supported
+                if (actionDefinitionId.equals(ChainActionDefinition.ID)) {
+                    result.put(PolicyManagerImpl.ActionCase.CHAIN, action);
+                    return result;
+                }
             }
         }
         return null;
     }
 
-    public static RenderedServicePath createSymmetricRenderedPath(ServiceFunctionPath sfp, RenderedServicePath rsp,
-                                                                  TenantId tenantId) {
-        RenderedServicePath reversedRenderedPath;
-        // Try to read existing RSP
-        RspName rspName = new RspName(sfp.getName().getValue() + tenantId.getValue() + "-gbp-rsp-Reverse");
-        reversedRenderedPath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
-        if (reversedRenderedPath != null) {
-            return reversedRenderedPath;
+    private static RuleGroup findRuleGroup(final Configuration data,
+                                           final RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation) {
+        final TenantId tenantId = ruleGroupWithParticipation.getTenantId();
+        final ContractId contractId = ruleGroupWithParticipation.getContractId();
+        final SubjectName subjectName = ruleGroupWithParticipation.getSubjectName();
+        for (RuleGroup ruleGroup : data.getRuleGroups().getRuleGroup()) {
+            if (!ruleGroup.getTenantId().equals(tenantId)) {
+                continue;
+            }
+            if (!ruleGroup.getContractId().equals(contractId)) {
+                continue;
+            }
+            if (ruleGroup.getSubjectName().equals(subjectName)) {
+                return ruleGroup;
+            }
         }
-        LOG.info("Reversed rendered service path with name {} not found, creating a new one ..", rspName.getValue());
-        reversedRenderedPath = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
-        LOG.info("Rendered service path {} created", rspName.getValue());
-        return reversedRenderedPath;
+        return null;
     }
 
 }
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/PolicyWriter.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/PolicyWriter.java
deleted file mode 100644 (file)
index f7827a4..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.ios_xe_provider.impl.util;
-
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
-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.ios.rev160308.Native;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMapKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PolicyWriter {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PolicyWriter.class);
-
-    private final DataBroker mountpoint;
-    // Local cache
-    private List<ClassMap> classMapEntries;
-    private List<Class> policyMapEntries;
-
-    public PolicyWriter(final DataBroker dataBroker) {
-        mountpoint = Preconditions.checkNotNull(dataBroker);
-        classMapEntries = new ArrayList<>();
-        policyMapEntries = new ArrayList<>();
-    }
-
-    public void write(ClassMap classMap) {
-        classMapEntries.add(classMap);
-    }
-
-    public void write(List<Class> policyMapEntries) {
-        this.policyMapEntries.addAll(policyMapEntries);
-    }
-
-    public void commitToDatastore() {
-        // create and write service-policy
-        // create and write policy-map with policyMapEntries
-        // create and write class-maps
-
-        WriteTransaction wtx = mountpoint.newWriteOnlyTransaction();
-        // Class maps
-        for (ClassMap entry : classMapEntries) {
-            InstanceIdentifier<ClassMap> iid = classMapInstanceIdentifier(entry);
-            try {
-                wtx.merge(LogicalDatastoreType.CONFIGURATION, iid, entry, true);
-                CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wtx.submit();
-                submitFuture.checkedGet();
-                // Clear cache
-                classMapEntries.clear();
-            } catch (TransactionCommitFailedException e) {
-                LOG.error("Write transaction failed to {}", e.getMessage());
-            } catch (Exception e) {
-                LOG.error("Failed to .. {}", e.getMessage());
-            }
-        }
-    }
-
-    private InstanceIdentifier<ClassMap> classMapInstanceIdentifier(ClassMap classMap) {
-        return InstanceIdentifier.builder(Native.class)
-                .child(ClassMap.class, new ClassMapKey(classMap.getName())).build();
-    }
-}
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/ServiceChainingUtil.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/ServiceChainingUtil.java
new file mode 100644 (file)
index 0000000..a83e593
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * 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.ios_xe_provider.impl.util;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriter;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308.Native;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChainBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.config.service.chain.grouping.IpBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.Local;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.LocalBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.ServiceIndexBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.Services;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.ServicesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.ServiceTypeChoice;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.service.type.choice.ServiceFunctionBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.config.service.chain.path.mode.service.index.services.service.type.choice.ServiceFunctionForwarderBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+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.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ServiceChainingUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceChainingUtil.class);
+
+    static ServiceFunctionPath getServicePath(final List<ParameterValue> params) {
+        if (params == null || params.isEmpty()) {
+            LOG.error("Cannot found service path, parameter value is null");
+            return null;
+        }
+        final Map<String, Object> paramsMap = new HashMap<>();
+        for (ParameterValue value : params) {
+            if (value.getName() == null)
+                continue;
+            if (value.getIntValue() != null) {
+                paramsMap.put(value.getName().getValue(), value.getIntValue());
+            } else if (value.getStringValue() != null) {
+                paramsMap.put(value.getName().getValue(), value.getStringValue());
+            }
+        }
+        String chainName = null;
+        for (String name : paramsMap.keySet()) {
+            if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
+                chainName = (String) paramsMap.get(name);
+            }
+        }
+        if (chainName == null) {
+            LOG.error("Cannot found service path, chain name is null");
+            return null;
+        }
+        final ServiceFunctionPath serviceFunctionPath = findServiceFunctionPath(new SfcName(chainName));
+        if (serviceFunctionPath == null) {
+            LOG.error("Service function path not found for name {}", chainName);
+            return null;
+        }
+        return serviceFunctionPath;
+    }
+
+    static void resolveChainAction(final PeerEndpointWithPolicy peerEndpoint, final Sgt sourceSgt,
+                                   final Sgt destinationSgt, final Map<PolicyManagerImpl.ActionCase, Action> actionMap,
+                                   final String classMapName, PolicyWriter policyWriter) {
+        final List<Class> entries = new ArrayList<>();
+        final Action action = actionMap.get(PolicyManagerImpl.ActionCase.CHAIN);
+        final ServiceFunctionPath servicePath = ServiceChainingUtil.getServicePath(action.getParameterValue());
+        if (servicePath == null) {
+            return;
+        }
+        final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
+        if (tenantId == null) {
+            return;
+        }
+        final RenderedServicePath renderedPath = ServiceChainingUtil.createRenderedPath(servicePath, tenantId);
+        // Create appropriate service path && remote forwarder
+        setSfcPart(renderedPath, policyWriter);
+
+        entries.add(PolicyManagerUtil.createPolicyEntry(classMapName, renderedPath, PolicyManagerImpl.ActionCase.CHAIN));
+        if (servicePath.isSymmetric()) {
+            // symmetric path is in opposite direction. Roles of renderer and peer endpoint will invert
+            RenderedServicePath symmetricPath = ServiceChainingUtil
+                    .createSymmetricRenderedPath(servicePath, renderedPath, tenantId);
+            final String oppositeClassMapName = PolicyManagerUtil.generateClassMapName(destinationSgt.getValue(), sourceSgt.getValue());
+            entries.add(PolicyManagerUtil.createPolicyEntry(oppositeClassMapName, symmetricPath, PolicyManagerImpl.ActionCase.CHAIN));
+        }
+        policyWriter.cache(entries);
+    }
+
+    static RenderedServicePath createRenderedPath(final ServiceFunctionPath sfp, final TenantId tenantId) {
+        RenderedServicePath renderedServicePath;
+        // Try to read existing RSP
+        final RspName rspName = new RspName(sfp.getName().getValue() + tenantId.getValue() + "-gbp-rsp");
+        renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
+        if (renderedServicePath != null) {
+            return renderedServicePath;
+        }
+        LOG.info("Rendered service path with name {} not found, creating a new one ..", rspName.getValue());
+        final CreateRenderedPathInput input = new CreateRenderedPathInputBuilder()
+                .setParentServiceFunctionPath(sfp.getName().getValue())
+                .setName(rspName.getValue())
+                .setSymmetric(sfp.isSymmetric())
+                .build();
+        renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, input);
+        LOG.info("Rendered service path {} created", rspName.getValue());
+        return renderedServicePath;
+    }
+
+    static RenderedServicePath createSymmetricRenderedPath(final ServiceFunctionPath sfp, final RenderedServicePath rsp,
+                                                           final TenantId tenantId) {
+        RenderedServicePath reversedRenderedPath;
+        // Try to read existing RSP
+        final RspName rspName = new RspName(sfp.getName().getValue() + tenantId.getValue() + "-gbp-rsp-Reverse");
+        reversedRenderedPath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
+        if (reversedRenderedPath != null) {
+            return reversedRenderedPath;
+        }
+        LOG.info("Reversed rendered service path with name {} not found, creating a new one ..", rspName.getValue());
+        reversedRenderedPath = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
+        LOG.info("Rendered service path {} created", rspName.getValue());
+        return reversedRenderedPath;
+    }
+
+    /**
+     * Method checks up, whether a {@link Local} Service Function Forwarder is present on device or not.
+     *
+     * @param mountpoint used to access specific device
+     * @return true if Local Forwarder is present, false otherwise
+     */
+    private static boolean checkLocalForwarderPresence(DataBroker mountpoint) {
+        InstanceIdentifier<Local> localSffIid = InstanceIdentifier.builder(Native.class)
+                .child(ServiceChain.class)
+                .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder.class)
+                .child(Local.class).build();
+        ReadWriteTransaction rwt = mountpoint.newReadWriteTransaction();
+        CheckedFuture<Optional<Local>, ReadFailedException> submitFuture = rwt.read(LogicalDatastoreType.CONFIGURATION,
+                localSffIid);
+        try {
+            Optional<Local> optionalLocalSff = submitFuture.checkedGet();
+            return optionalLocalSff.isPresent();
+        } catch (ReadFailedException e) {
+            LOG.warn("Read transaction failed to {} ", e);
+        } catch (Exception e) {
+            LOG.error("Failed to .. {}", e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * Method checks up, if some {@link ServicePath} is present on device.
+     *
+     * @param mountpoint used to access specific device
+     * @return true if service chain does not exist, is null or does not contain any service path. False otherwise
+     */
+    public static boolean checkServicePathPresence(DataBroker mountpoint) {
+        InstanceIdentifier<ServiceChain> serviceChainIid = InstanceIdentifier.builder(Native.class)
+                .child(ServiceChain.class).build();
+        ReadWriteTransaction rwt = mountpoint.newReadWriteTransaction();
+        CheckedFuture<Optional<ServiceChain>, ReadFailedException> submitFuture = rwt.read(LogicalDatastoreType.CONFIGURATION,
+                serviceChainIid);
+        try {
+            Optional<ServiceChain> optionalServiceChain = submitFuture.checkedGet();
+            if (optionalServiceChain.isPresent()) {
+                ServiceChain chain = optionalServiceChain.get();
+                return chain == null || chain.getServicePath() == null || chain.getServicePath().isEmpty();
+            } else {
+                return true;
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Read transaction failed to {} ", e);
+        } catch (Exception e) {
+            LOG.error("Failed to .. {}", e.getMessage());
+        }
+        return false;
+    }
+
+    private static ServiceFunctionPath findServiceFunctionPath(final SfcName chainName) {
+        final ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
+        for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
+            if (serviceFunctionPath.getServiceChainName().equals(chainName)) {
+                return serviceFunctionPath;
+            }
+        }
+        return null;
+    }
+
+    private static void setSfcPart(final RenderedServicePath renderedServicePath, PolicyWriter policyWriter) {
+        if (renderedServicePath != null && renderedServicePath.getRenderedServicePathHop() != null &&
+                !renderedServicePath.getRenderedServicePathHop().isEmpty()) {
+            final RenderedServicePathHop firstHop = renderedServicePath.getRenderedServicePathHop().get(0);
+            if (firstHop == null) {
+                LOG.error("Rendered service path {} does not contain any hop", renderedServicePath.getName().getValue());
+                return;
+            }
+            final SffName sffName = firstHop.getServiceFunctionForwarder();
+            final ServiceFunctionForwarder serviceFunctionForwarder = SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName);
+            if (serviceFunctionForwarder == null) {
+                LOG.error("Sff with name {} does not exist", sffName.getValue());
+                return;
+            }
+            // Forwarders
+            //
+            // If classifier node is also forwarder, first entry in service path has to point to first service function
+            // (Local case)
+            //
+            // If first hop Sff is on different node, first service path entry has to point to that specific service
+            // forwarder (Remote case)
+
+            // Local case (only when does not exist)
+
+            if (!checkLocalForwarderPresence(policyWriter.getCurrentMountpoint())) {
+                final LocalBuilder localSffBuilder = new LocalBuilder();
+                localSffBuilder.setIp(new IpBuilder().setAddress(new Ipv4Address(policyWriter.getManagementIpAddress()))
+                        .build());
+                policyWriter.cache(localSffBuilder.build());
+            } else {
+                LOG.info("Local forwarder for node {} is already created", policyWriter.getCurrentNodeId());
+            }
+            // Set up choice. If remote, this choice is overwritten
+            ServiceTypeChoice serviceTypeChoice = functionTypeChoice(firstHop.getServiceFunctionName().getValue());
+            // Remote case
+            if (serviceFunctionForwarder.getIpMgmtAddress() == null
+                    || serviceFunctionForwarder.getIpMgmtAddress().getIpv4Address() == null) {
+                LOG.error("Cannot create remote forwarder, SFF {} does not contain management ip address",
+                        sffName.getValue());
+                return;
+            }
+            final String sffMgmtIpAddress = serviceFunctionForwarder.getIpMgmtAddress().getIpv4Address().getValue();
+            // If local SFF has the same ip as first hop sff, it's the same SFF; no need to create a remote one
+            if (!sffMgmtIpAddress.equals(policyWriter.getManagementIpAddress())) {
+                final ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
+                remoteSffBuilder.setName(sffName.getValue())
+                        .setKey(new ServiceFfNameKey(sffName.getValue()))
+                        .setIp(new IpBuilder().setAddress(new Ipv4Address(sffMgmtIpAddress)).build());
+                policyWriter.cache(remoteSffBuilder.build());
+                serviceTypeChoice = forwarderTypeChoice(sffName.getValue());
+            }
+
+            // Service chain
+            final List<Services> services = new ArrayList<>();
+            final ServicesBuilder servicesBuilder = new ServicesBuilder();
+            servicesBuilder.setServiceIndexId(renderedServicePath.getStartingIndex())
+                    .setServiceTypeChoice(serviceTypeChoice);
+            final List<ServicePath> servicePaths = new ArrayList<>();
+            final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
+            servicePathBuilder.setKey(new ServicePathKey(renderedServicePath.getPathId()))
+                    .setServicePathId(renderedServicePath.getPathId())
+                    .setConfigServiceChainPathMode(new ConfigServiceChainPathModeBuilder()
+                            .setServiceIndex(new ServiceIndexBuilder()
+                                    .setServices(services).build()).build());
+            servicePaths.add(servicePathBuilder.build());
+            final ServiceChainBuilder chainBuilder = new ServiceChainBuilder();
+            chainBuilder.setServicePath(servicePaths);
+            final ServiceChain serviceChain = chainBuilder.build();
+            policyWriter.cache(serviceChain);
+        }
+    }
+
+    private static ServiceTypeChoice forwarderTypeChoice(final String forwarderName) {
+        final ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
+        sffBuilder.setServiceFunctionForwarder(forwarderName);
+        return sffBuilder.build();
+    }
+
+    private static ServiceTypeChoice functionTypeChoice(final String functionName) {
+        final ServiceFunctionBuilder sfBuilder = new ServiceFunctionBuilder();
+        sfBuilder.setServiceFunction(functionName);
+        return sfBuilder.build();
+    }
+
+}
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util;
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer;
 
 import com.google.common.util.concurrent.CheckedFuture;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
diff --git a/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/writer/PolicyWriter.java b/renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/writer/PolicyWriter.java
new file mode 100644 (file)
index 0000000..bf7bb2a
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * 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.ios_xe_provider.impl.writer;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+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.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.ServiceChainingUtil;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308.Native;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.ServicePolicy;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.type.ServiceChain.Direction;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMapKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.Interface;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMap;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMapKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._interface.GigabitEthernet;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._interface.GigabitEthernetKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.Local;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfName;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PolicyWriter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PolicyWriter.class);
+
+    private final DataBroker mountpoint;
+    // Local cache
+    private final List<ClassMap> classMapEntries;
+    private final List<Class> policyMapEntries;
+    private final List<ServiceFfName> remoteForwarders;
+    private final List<ServiceChain> serviceChains;
+    private final NodeId nodeId;
+    private final String interfaceName;
+    private final String policyMapName;
+    private final String managementIpAddress;
+    private Local localForwarder;
+
+    public PolicyWriter(final DataBroker dataBroker, final String interfaceName, final String ipAddress,
+                        final String policyMapName, final NodeId nodeId) {
+        classMapEntries = new ArrayList<>();
+        policyMapEntries = new ArrayList<>();
+        remoteForwarders = new ArrayList<>();
+        serviceChains = new ArrayList<>();
+
+        this.nodeId = Preconditions.checkNotNull(nodeId);
+        mountpoint = Preconditions.checkNotNull(dataBroker);
+        managementIpAddress = Preconditions.checkNotNull(ipAddress);
+        this.interfaceName = Preconditions.checkNotNull(interfaceName);
+        this.policyMapName = Preconditions.checkNotNull(policyMapName);
+    }
+
+    public void cache(ClassMap classMap) {
+        classMapEntries.add(classMap);
+    }
+
+    public void cache(List<Class> policyMapEntries) {
+        this.policyMapEntries.addAll(policyMapEntries);
+    }
+
+    public void cache(Local localForwarder) {
+        this.localForwarder = localForwarder;
+    }
+
+    public void cache(ServiceFfName remoteForwarder) {
+        remoteForwarders.add(remoteForwarder);
+    }
+
+    public void cache(ServiceChain serviceChain) {
+        serviceChains.add(serviceChain);
+    }
+
+    public void commitToDatastore() {
+        WriteTransaction wtx = mountpoint.newWriteOnlyTransaction();
+        // GBP
+        // Class maps
+        for (ClassMap entry : classMapEntries) {
+            InstanceIdentifier<ClassMap> classMapIid = classMapInstanceIdentifier(entry);
+            wtx.merge(LogicalDatastoreType.CONFIGURATION, classMapIid, entry);
+            LOG.info("Created class-map {} on node {}", entry.getName(), nodeId.getValue());
+        }
+
+        // Policy map
+        PolicyMap policyMap = PolicyManagerUtil.createPolicyMap(policyMapName, policyMapEntries);
+        InstanceIdentifier<PolicyMap> policyMapIid = policyMapInstanceIdentifier();
+        wtx.merge(LogicalDatastoreType.CONFIGURATION, policyMapIid, policyMap);
+        LOG.info("Created policy-map {} on node {}", policyMap.getName(), nodeId.getValue());
+
+        // Interface
+        ServicePolicy servicePolicy = PolicyManagerUtil.createServicePolicy(policyMapName, Direction.Input);
+        InstanceIdentifier<ServicePolicy> servicePolicyIid = interfaceInstanceIdentifier(interfaceName);
+        wtx.merge(LogicalDatastoreType.CONFIGURATION, servicePolicyIid, servicePolicy);
+        LOG.info("Service-policy interface {}, bound to policy-map {} created on  node {}",
+                interfaceName, policyMap.getName(), nodeId.getValue());
+
+        //SFC
+        // Local forwarder (if some service chain exists, otherwise is useless)
+        if (!serviceChains.isEmpty()) {
+            InstanceIdentifier<Local> localIid = localSffInstanceIdentifier();
+            wtx.merge(LogicalDatastoreType.CONFIGURATION, localIid, localForwarder);
+            LOG.info("Local forwarder created on node {}", nodeId.getValue());
+        }
+
+        // Remote forwarders
+        for (ServiceFfName forwarder : remoteForwarders) {
+            InstanceIdentifier<ServiceFfName> forwarderIid = remoteSffInstanceIdentifier(forwarder);
+            wtx.merge(LogicalDatastoreType.CONFIGURATION, forwarderIid, forwarder);
+            LOG.info("Remote forwarder {} created on node {}", forwarder.getName(), nodeId.getValue());
+        }
+
+        // Service paths
+        for (ServiceChain serviceChain : serviceChains) {
+            for (ServicePath entry : serviceChain.getServicePath()) {
+                InstanceIdentifier<ServicePath> servicePathIid = servicePathInstanceIdentifier(entry.getKey());
+                wtx.merge(LogicalDatastoreType.CONFIGURATION, servicePathIid, entry);
+                LOG.info("Service path with Id {} created on node {}", entry.getServicePathId(), nodeId.getValue());
+            }
+        }
+
+        try {
+            CheckedFuture<Void, TransactionCommitFailedException> 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());
+        }
+    }
+
+    public void removeFromDatastore() {
+        ReadWriteTransaction wtx = mountpoint.newReadWriteTransaction();
+        //GBP
+        // Interface
+        InstanceIdentifier<ServicePolicy> servicePolicyIid = interfaceInstanceIdentifier(interfaceName);
+        wtx.delete(LogicalDatastoreType.CONFIGURATION, servicePolicyIid);
+        LOG.info("Service-policy removed from interface {} on node {}", interfaceName, nodeId.getValue());
+
+        // Policy map
+        InstanceIdentifier<PolicyMap> policyMapIid = policyMapInstanceIdentifier();
+        wtx.delete(LogicalDatastoreType.CONFIGURATION, policyMapIid);
+        LOG.info("Policy-map removed from node node {}", nodeId.getValue());
+
+        // Class map
+        for (ClassMap entry : classMapEntries) {
+            InstanceIdentifier<ClassMap> classMapIid = classMapInstanceIdentifier(entry);
+            wtx.delete(LogicalDatastoreType.CONFIGURATION, classMapIid);
+            LOG.info("Class-map {} removed from node {}", entry.getName(), nodeId.getValue());
+        }
+
+        //SFC
+        // Service paths
+        for (ServiceChain serviceChain : serviceChains) {
+            for (ServicePath entry : serviceChain.getServicePath()) {
+                InstanceIdentifier<ServicePath> servicePathIid = servicePathInstanceIdentifier(entry.getKey());
+                wtx.delete(LogicalDatastoreType.CONFIGURATION, servicePathIid);
+                LOG.info("Service path with Id {} removed from node {}", entry.getServicePathId(), nodeId.getValue());
+            }
+        }
+
+        // Remote forwarders
+        for (ServiceFfName forwarder : remoteForwarders) {
+            InstanceIdentifier<ServiceFfName> forwarderIid = remoteSffInstanceIdentifier(forwarder);
+            wtx.delete(LogicalDatastoreType.CONFIGURATION, forwarderIid);
+            LOG.info("Remote forwarder {} removed from node {}", forwarder.getName(), nodeId.getValue());
+        }
+
+        // Local forwarder - remove only if there is no more service-paths on device. If paths removed above were last
+        // ones, remove local forwarder. If there are still some paths present, they were created by sfc and local
+        // forwarder cannot be removed (because it was created by sfc as well)
+        if (ServiceChainingUtil.checkServicePathPresence(mountpoint)) {
+            InstanceIdentifier<Local> localIid = localSffInstanceIdentifier();
+            wtx.delete(LogicalDatastoreType.CONFIGURATION, localIid);
+            LOG.info("Local forwarder removed from node {}", nodeId.getValue());
+        }
+
+        try {
+            CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wtx.submit();
+            submitFuture.checkedGet();
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("Write transaction failed to {}", e.getMessage());
+        } catch (Exception e) {
+            LOG.error("Failed to .. {}", e.getMessage());
+        }
+    }
+
+    private InstanceIdentifier<ClassMap> classMapInstanceIdentifier(ClassMap classMap) {
+        return InstanceIdentifier.builder(Native.class)
+                .child(ClassMap.class, new ClassMapKey(classMap.getName())).build();
+    }
+
+    private InstanceIdentifier<PolicyMap> policyMapInstanceIdentifier() {
+        return InstanceIdentifier.builder(Native.class)
+                .child(PolicyMap.class, new PolicyMapKey(policyMapName)).build();
+    }
+
+    private InstanceIdentifier<ServicePolicy> interfaceInstanceIdentifier(String ethernetName) {
+        return InstanceIdentifier.builder(Native.class)
+                .child(Interface.class)
+                .child(GigabitEthernet.class, new GigabitEthernetKey(ethernetName))
+                .child(ServicePolicy.class)
+                .build();
+    }
+
+    private InstanceIdentifier<Local> localSffInstanceIdentifier() {
+        return InstanceIdentifier.builder(Native.class)
+                .child(ServiceChain.class)
+                .child(ServiceFunctionForwarder.class)
+                .child(Local.class).build();
+    }
+
+    private InstanceIdentifier<ServiceFfName> remoteSffInstanceIdentifier(ServiceFfName sffName) {
+        return InstanceIdentifier.builder(Native.class)
+                .child(ServiceChain.class)
+                .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder.class)
+                .child(ServiceFfName.class, new ServiceFfNameKey(sffName.getName())).build();
+    }
+
+    private InstanceIdentifier<ServicePath> servicePathInstanceIdentifier(ServicePathKey key) {
+        return InstanceIdentifier.builder(Native.class)
+                .child(ServiceChain.class)
+                .child(ServicePath.class, key).build();
+    }
+
+    public String getManagementIpAddress() {
+        return managementIpAddress;
+    }
+
+    public DataBroker getCurrentMountpoint() {
+        return mountpoint;
+    }
+
+    public NodeId getCurrentNodeId() {
+        return nodeId;
+    }
+}
diff --git a/renderers/ios-xe/src/main/yang/netconf/ietf-inet-types.yang b/renderers/ios-xe/src/main/yang/netconf/ietf-inet-types.yang
deleted file mode 100644 (file)
index 5624a95..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-module ietf-inet-types {
-
-  namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
-  prefix "inet";
-
-  organization
-   "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
-
-  contact
-   "WG Web:   <http://tools.ietf.org/wg/netmod/>
-    WG List:  <mailto:netmod@ietf.org>
-
-    WG Chair: David Kessens
-              <mailto:david.kessens@nsn.com>
-
-    WG Chair: Juergen Schoenwaelder
-              <mailto:j.schoenwaelder@jacobs-university.de>
-
-    Editor:   Juergen Schoenwaelder
-              <mailto:j.schoenwaelder@jacobs-university.de>";
-
-  description
-   "This module contains a collection of generally useful derived
-    YANG data types for Internet addresses and related things.
-
-    Copyright (c) 2013 IETF Trust and the persons identified as
-    authors of the code.  All rights reserved.
-
-    Redistribution and use in source and binary forms, with or
-    without modification, is permitted pursuant to, and subject
-    to the license terms contained in, the Simplified BSD License
-    set forth in Section 4.c of the IETF Trust's Legal Provisions
-    Relating to IETF Documents
-    (http://trustee.ietf.org/license-info).
-
-    This version of this YANG module is part of RFC 6991; see
-    the RFC itself for full legal notices.";
-
-  revision 2013-07-15 {
-    description
-     "This revision adds the following new data types:
-      - ip-address-no-zone
-      - ipv4-address-no-zone
-      - ipv6-address-no-zone";
-    reference
-     "RFC 6991: Common YANG Data Types";
-  }
-
-  revision 2010-09-24 {
-    description
-     "Initial revision.";
-    reference
-     "RFC 6021: Common YANG Data Types";
-  }
-
-  /*** collection of types related to protocol fields ***/
-
-  typedef ip-version {
-    type enumeration {
-      enum unknown {
-        value "0";
-        description
-         "An unknown or unspecified version of the Internet
-          protocol.";
-      }
-      enum ipv4 {
-        value "1";
-        description
-         "The IPv4 protocol as defined in RFC 791.";
-      }
-      enum ipv6 {
-        value "2";
-        description
-         "The IPv6 protocol as defined in RFC 2460.";
-      }
-    }
-    description
-     "This value represents the version of the IP protocol.
-
-      In the value set and its semantics, this type is equivalent
-      to the InetVersion textual convention of the SMIv2.";
-    reference
-     "RFC  791: Internet Protocol
-      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
-      RFC 4001: Textual Conventions for Internet Network Addresses";
-  }
-
-  typedef dscp {
-    type uint8 {
-      range "0..63";
-    }
-    description
-     "The dscp type represents a Differentiated Services Code Point
-      that may be used for marking packets in a traffic stream.
-      In the value set and its semantics, this type is equivalent
-      to the Dscp textual convention of the SMIv2.";
-    reference
-     "RFC 3289: Management Information Base for the Differentiated
-                Services Architecture
-      RFC 2474: Definition of the Differentiated Services Field
-                (DS Field) in the IPv4 and IPv6 Headers
-      RFC 2780: IANA Allocation Guidelines For Values In
-                the Internet Protocol and Related Headers";
-  }
-
-  typedef ipv6-flow-label {
-    type uint32 {
-      range "0..1048575";
-    }
-    description
-     "The ipv6-flow-label type represents the flow identifier or Flow
-      Label in an IPv6 packet header that may be used to
-      discriminate traffic flows.
-
-      In the value set and its semantics, this type is equivalent
-      to the IPv6FlowLabel textual convention of the SMIv2.";
-    reference
-     "RFC 3595: Textual Conventions for IPv6 Flow Label
-      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
-  }
-
-  typedef port-number {
-    type uint16 {
-      range "0..65535";
-    }
-    description
-     "The port-number type represents a 16-bit port number of an
-      Internet transport-layer protocol such as UDP, TCP, DCCP, or
-      SCTP.  Port numbers are assigned by IANA.  A current list of
-      all assignments is available from <http://www.iana.org/>.
-
-      Note that the port number value zero is reserved by IANA.  In
-      situations where the value zero does not make sense, it can
-      be excluded by subtyping the port-number type.
-      In the value set and its semantics, this type is equivalent
-      to the InetPortNumber textual convention of the SMIv2.";
-    reference
-     "RFC  768: User Datagram Protocol
-      RFC  793: Transmission Control Protocol
-      RFC 4960: Stream Control Transmission Protocol
-      RFC 4340: Datagram Congestion Control Protocol (DCCP)
-      RFC 4001: Textual Conventions for Internet Network Addresses";
-  }
-
-  /*** collection of types related to autonomous systems ***/
-
-  typedef as-number {
-    type uint32;
-    description
-     "The as-number type represents autonomous system numbers
-      which identify an Autonomous System (AS).  An AS is a set
-      of routers under a single technical administration, using
-      an interior gateway protocol and common metrics to route
-      packets within the AS, and using an exterior gateway
-      protocol to route packets to other ASes.  IANA maintains
-      the AS number space and has delegated large parts to the
-      regional registries.
-
-      Autonomous system numbers were originally limited to 16
-      bits.  BGP extensions have enlarged the autonomous system
-      number space to 32 bits.  This type therefore uses an uint32
-      base type without a range restriction in order to support
-      a larger autonomous system number space.
-
-      In the value set and its semantics, this type is equivalent
-      to the InetAutonomousSystemNumber textual convention of
-      the SMIv2.";
-    reference
-     "RFC 1930: Guidelines for creation, selection, and registration
-                of an Autonomous System (AS)
-      RFC 4271: A Border Gateway Protocol 4 (BGP-4)
-      RFC 4001: Textual Conventions for Internet Network Addresses
-      RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
-                Number Space";
-  }
-
-  /*** collection of types related to IP addresses and hostnames ***/
-
-  typedef ip-address {
-    type union {
-      type inet:ipv4-address;
-      type inet:ipv6-address;
-    }
-    description
-     "The ip-address type represents an IP address and is IP
-      version neutral.  The format of the textual representation
-      implies the IP version.  This type supports scoped addresses
-      by allowing zone identifiers in the address format.";
-    reference
-     "RFC 4007: IPv6 Scoped Address Architecture";
-  }
-
-  typedef ipv4-address {
-    type string {
-      pattern
-        '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
-      +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
-      + '(%[\p{N}\p{L}]+)?';
-    }
-    description
-      "The ipv4-address type represents an IPv4 address in
-       dotted-quad notation.  The IPv4 address may include a zone
-       index, separated by a % sign.
-
-       The zone index is used to disambiguate identical address
-       values.  For link-local addresses, the zone index will
-       typically be the interface index number or the name of an
-       interface.  If the zone index is not present, the default
-       zone of the device will be used.
-
-       The canonical format for the zone index is the numerical
-       format";
-  }
-
-  typedef ipv6-address {
-    type string {
-      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
-            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
-            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
-            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
-            + '(%[\p{N}\p{L}]+)?';
-      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
-            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
-            + '(%.+)?';
-    }
-    description
-     "The ipv6-address type represents an IPv6 address in full,
-      mixed, shortened, and shortened-mixed notation.  The IPv6
-      address may include a zone index, separated by a % sign.
-
-      The zone index is used to disambiguate identical address
-      values.  For link-local addresses, the zone index will
-      typically be the interface index number or the name of an
-      interface.  If the zone index is not present, the default
-      zone of the device will be used.
-
-
-
-      The canonical format of IPv6 addresses uses the textual
-      representation defined in Section 4 of RFC 5952.  The
-      canonical format for the zone index is the numerical
-      format as described in Section 11.2 of RFC 4007.";
-    reference
-     "RFC 4291: IP Version 6 Addressing Architecture
-      RFC 4007: IPv6 Scoped Address Architecture
-      RFC 5952: A Recommendation for IPv6 Address Text
-                Representation";
-  }
-
-  typedef ip-address-no-zone {
-    type union {
-      type inet:ipv4-address-no-zone;
-      type inet:ipv6-address-no-zone;
-    }
-    description
-     "The ip-address-no-zone type represents an IP address and is
-      IP version neutral.  The format of the textual representation
-      implies the IP version.  This type does not support scoped
-      addresses since it does not allow zone identifiers in the
-      address format.";
-    reference
-     "RFC 4007: IPv6 Scoped Address Architecture";
-  }
-
-  typedef ipv4-address-no-zone {
-    type inet:ipv4-address {
-      pattern '[0-9\.]*';
-    }
-    description
-      "An IPv4 address without a zone index.  This type, derived from
-       ipv4-address, may be used in situations where the zone is
-       known from the context and hence no zone index is needed.";
-  }
-
-  typedef ipv6-address-no-zone {
-    type inet:ipv6-address {
-      pattern '[0-9a-fA-F:\.]*';
-    }
-    description
-      "An IPv6 address without a zone index.  This type, derived from
-       ipv6-address, may be used in situations where the zone is
-       known from the context and hence no zone index is needed.";
-    reference
-     "RFC 4291: IP Version 6 Addressing Architecture
-      RFC 4007: IPv6 Scoped Address Architecture
-      RFC 5952: A Recommendation for IPv6 Address Text
-                Representation";
-  }
-
-  typedef ip-prefix {
-    type union {
-      type inet:ipv4-prefix;
-      type inet:ipv6-prefix;
-    }
-    description
-     "The ip-prefix type represents an IP prefix and is IP
-      version neutral.  The format of the textual representations
-      implies the IP version.";
-  }
-
-  typedef ipv4-prefix {
-    type string {
-      pattern
-         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
-       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
-       + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
-    }
-    description
-     "The ipv4-prefix type represents an IPv4 address prefix.
-      The prefix length is given by the number following the
-      slash character and must be less than or equal to 32.
-
-      A prefix length value of n corresponds to an IP address
-      mask that has n contiguous 1-bits from the most
-      significant bit (MSB) and all other bits set to 0.
-
-      The canonical format of an IPv4 prefix has all bits of
-      the IPv4 address set to zero that are not part of the
-      IPv4 prefix.";
-  }
-
-  typedef ipv6-prefix {
-    type string {
-      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
-            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
-            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
-            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
-            + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
-      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
-            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
-            + '(/.+)';
-    }
-
-
-    description
-     "The ipv6-prefix type represents an IPv6 address prefix.
-      The prefix length is given by the number following the
-      slash character and must be less than or equal to 128.
-
-      A prefix length value of n corresponds to an IP address
-      mask that has n contiguous 1-bits from the most
-      significant bit (MSB) and all other bits set to 0.
-
-      The IPv6 address should have all bits that do not belong
-      to the prefix set to zero.
-
-      The canonical format of an IPv6 prefix has all bits of
-      the IPv6 address set to zero that are not part of the
-      IPv6 prefix.  Furthermore, the IPv6 address is represented
-      as defined in Section 4 of RFC 5952.";
-    reference
-     "RFC 5952: A Recommendation for IPv6 Address Text
-                Representation";
-  }
-
-  /*** collection of domain name and URI types ***/
-
-  typedef domain-name {
-    type string {
-      pattern
-        '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
-      + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
-      + '|\.';
-      length "1..253";
-    }
-    description
-     "The domain-name type represents a DNS domain name.  The
-      name SHOULD be fully qualified whenever possible.
-
-      Internet domain names are only loosely specified.  Section
-      3.5 of RFC 1034 recommends a syntax (modified in Section
-      2.1 of RFC 1123).  The pattern above is intended to allow
-      for current practice in domain name use, and some possible
-      future expansion.  It is designed to hold various types of
-      domain names, including names used for A or AAAA records
-      (host names) and other records, such as SRV records.  Note
-      that Internet host names have a stricter syntax (described
-      in RFC 952) than the DNS recommendations in RFCs 1034 and
-      1123, and that systems that want to store host names in
-      schema nodes using the domain-name type are recommended to
-      adhere to this stricter standard to ensure interoperability.
-
-      The encoding of DNS names in the DNS protocol is limited
-      to 255 characters.  Since the encoding consists of labels
-      prefixed by a length bytes and there is a trailing NULL
-      byte, only 253 characters can appear in the textual dotted
-      notation.
-
-      The description clause of schema nodes using the domain-name
-      type MUST describe when and how these names are resolved to
-      IP addresses.  Note that the resolution of a domain-name value
-      may require to query multiple DNS records (e.g., A for IPv4
-      and AAAA for IPv6).  The order of the resolution process and
-      which DNS record takes precedence can either be defined
-      explicitly or may depend on the configuration of the
-      resolver.
-
-      Domain-name values use the US-ASCII encoding.  Their canonical
-      format uses lowercase US-ASCII characters.  Internationalized
-      domain names MUST be A-labels as per RFC 5890.";
-    reference
-     "RFC  952: DoD Internet Host Table Specification
-      RFC 1034: Domain Names - Concepts and Facilities
-      RFC 1123: Requirements for Internet Hosts -- Application
-                and Support
-      RFC 2782: A DNS RR for specifying the location of services
-                (DNS SRV)
-      RFC 5890: Internationalized Domain Names in Applications
-                (IDNA): Definitions and Document Framework";
-  }
-
-  typedef host {
-    type union {
-      type inet:ip-address;
-      type inet:domain-name;
-    }
-    description
-     "The host type represents either an IP address or a DNS
-      domain name.";
-  }
-
-  typedef uri {
-    type string;
-    description
-     "The uri type represents a Uniform Resource Identifier
-      (URI) as defined by STD 66.
-
-      Objects using the uri type MUST be in US-ASCII encoding,
-      and MUST be normalized as described by RFC 3986 Sections
-      6.2.1, 6.2.2.1, and 6.2.2.2.  All unnecessary
-      percent-encoding is removed, and all case-insensitive
-      characters are set to lowercase except for hexadecimal
-      digits, which are normalized to uppercase as described in
-      Section 6.2.2.1.
-
-      The purpose of this normalization is to help provide
-      unique URIs.  Note that this normalization is not
-      sufficient to provide uniqueness.  Two URIs that are
-      textually distinct after this normalization may still be
-      equivalent.
-
-      Objects using the uri type may restrict the schemes that
-      they permit.  For example, 'data:' and 'urn:' schemes
-      might not be appropriate.
-
-      A zero-length URI is not a valid URI.  This can be used to
-      express 'URI absent' where required.
-
-      In the value set and its semantics, this type is equivalent
-      to the Uri SMIv2 textual convention defined in RFC 5017.";
-    reference
-     "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
-      RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
-                Group: Uniform Resource Identifiers (URIs), URLs,
-                and Uniform Resource Names (URNs): Clarifications
-                and Recommendations
-      RFC 5017: MIB Textual Conventions for Uniform Resource
-                Identifiers (URIs)";
-  }
-
-}
\ No newline at end of file
index 5c51b7c16364a8266f189db1fb60282f19823094..7e394d6a34c6de95109b3de19f752c32116e51f2 100644 (file)
@@ -1735,29 +1735,6 @@ module ned {
         }
     }
 
-    grouping config-service-chain-grouping {
-        leaf description {
-            tailf:info "Service function forwarder description";
-            description "Service function forwarder description";
-            tailf:cli-multi-value;
-            type string {
-                tailf:info "LINE;;Up to 256 characters describing this " + "service function forwarder";
-                length "1..256";
-            }
-        }
-        container ip {
-            tailf:info "IP address for Service Function Forwarder";
-            description "IP address for Service Function Forwarder";
-            leaf address {
-                tailf:info "Set IPv4 address";
-                description "Set IPv4 address";
-                type inet:ipv4-address {
-                    tailf:info "A.B.C.D;;IP address of Service Function Forwarder";
-                }
-            }
-        }
-    }
-
     grouping interface-atm-grouping {
         // Removed body
     }
@@ -6619,6 +6596,29 @@ module ned {
 /// service-chain
 /// ========================================================================
 
+        grouping config-service-chain-grouping {
+            leaf description {
+                tailf:info "Service function forwarder description";
+                description "Service function forwarder description";
+                tailf:cli-multi-value;
+                type string {
+                    tailf:info "LINE;;Up to 256 characters describing this " + "service function forwarder";
+                    length "1..256";
+                }
+            }
+            container ip {
+                tailf:info "IP address for Service Function Forwarder";
+                description "IP address for Service Function Forwarder";
+                leaf address {
+                    tailf:info "Set IPv4 address";
+                    description "Set IPv4 address";
+                    type inet:ipv4-address {
+                        tailf:info "A.B.C.D;;IP address of Service Function Forwarder";
+                    }
+                }
+            }
+        }
+
         container service-chain {
             tailf:info "Service Chain mode";
             description "Service Chain mode";
diff --git a/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/NodeManagerTest.java b/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/NodeManagerTest.java
new file mode 100644 (file)
index 0000000..98aec52
--- /dev/null
@@ -0,0 +1,356 @@
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+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.test.CustomDataBrokerTest;
+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.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;
+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.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.AvailableCapabilities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder;
+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.NodeId;
+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.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 javax.annotation.Nonnull;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+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 static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.UnableToConnect;
+
+
+public class NodeManagerTest extends CustomDataBrokerTest {
+
+    private final NodeId NODE_NAME = new NodeId("testNode");
+    private final TopologyId TOPOLOGY_ID = new TopologyId("topology-netconf");
+    private final Ipv4Address IPv4_ADDRESS = new Ipv4Address("174.25.75.11");
+    private NodeManager nodeManager;
+    private DataBroker dataBroker;
+
+    @Nonnull
+    @Override
+    public Collection<java.lang.Class<?>> getClassesFromModules() {
+        return Arrays.asList(Renderers.class, NetworkTopology.class, NetconfNode.class);
+    }
+
+    @Before
+    public void init() {
+        dataBroker = getDataBroker();
+        BindingAwareBroker.ProviderContext context = mock(BindingAwareBroker.ProviderContext.class);
+        MountPointService mountPointService = mock(MountPointService.class);
+        when(context.getSALService(any())).thenReturn(mountPointService);
+        nodeManager = new NodeManager(dataBroker, context);
+    }
+
+    @Test
+    public void testRegisterNewNode_connectingCase() throws Exception {
+        Node testNode = createNode(Connecting, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(testNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    // Create Cases
+
+    @Test
+    public void testRegisterNewNode_connectedCaseNoIpAddress() throws Exception {
+        Node testNode = createNode(Connected, null, NODE_NAME, Capabilities.None);
+        nodeManager.syncNodes(testNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testRegisterNewNode_connectedCaseNullCapabilities() throws Exception {
+        Node testNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.None);
+        nodeManager.syncNodes(testNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testRegisterNewNode_connectedCasePartialCapabilities() throws Exception {
+        Node testNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Partial);
+        nodeManager.syncNodes(testNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testRegisterNewNode_connectedCaseFullCapabilities() throws Exception {
+        Node testNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(testNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertNotNull(result);
+        assertTrue(result.size() == 1);
+    }
+
+    @Test
+    public void testRegisterNewNode_unableToConnectCase() throws Exception {
+        Node testNode = createNode(UnableToConnect, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(testNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testUpdateNode_fromConnectingToConnected() throws Exception {
+        Node oldNode = createNode(Connecting, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        Node newNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(oldNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        assertNotNull(result);
+        assertTrue(result.size() == 1);
+    }
+
+    // Update Cases
+
+    @Test
+    public void testUpdateNode_fromConnectingToUnableToConnect() throws Exception {
+        Node oldNode = createNode(Connecting, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        Node newNode = createNode(UnableToConnect, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(oldNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testUpdateNode_fromConnectedToConnecting() throws Exception {
+        Node oldNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        Node newNode = createNode(Connecting, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(oldNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertNotNull(result);
+        assertTrue(result.size() == 1);
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testUpdateNode_fromConnectedToUnableToConnect() throws Exception {
+        Node oldNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        Node newNode = createNode(UnableToConnect, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(oldNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertNotNull(result);
+        assertTrue(result.size() == 1);
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testUpdateNode_fromUnableToConnectToConnecting() throws Exception {
+        Node oldNode = createNode(UnableToConnect, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        Node newNode = createNode(Connecting, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(oldNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testUpdateNode_fromUnableToConnectToConnected() throws Exception {
+        Node oldNode = createNode(UnableToConnect, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        Node newNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(oldNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        assertNotNull(result);
+        assertTrue(result.size() == 1);
+    }
+
+    @Test
+    public void testUpdateNode_advancedCase() throws Exception {
+        Node oldNode = createNode(Connecting, IPv4_ADDRESS, NODE_NAME, Capabilities.Partial);
+        nodeManager.syncNodes(oldNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        // One node is connecting, partial capabilities = empty list
+        assertTrue(result.isEmpty());
+        Node newNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Partial);
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        // Update 1.: node is connected, still partial capabilities = empty list
+        assertTrue(result.isEmpty());
+        oldNode = newNode;
+        newNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        // Update 2.: node is connected, full capabilities = 1 entry in list
+        assertNotNull(result);
+        assertTrue(result.size() == 1);
+        oldNode = newNode;
+        newNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.None);
+        nodeManager.syncNodes(newNode, oldNode);
+        result = rendererNodesReader();
+        // Update 3.: node remains connected, but without capabilities = empty list
+        assertTrue(result.isEmpty());
+    }
+
+    // Advanced update Case
+
+    @Test
+    public void testRemoveNode() throws Exception {
+        Node testNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        nodeManager.syncNodes(testNode, null);
+        List<RendererNode> result = rendererNodesReader();
+        assertNotNull(result);
+        assertTrue(result.size() == 1);
+        nodeManager.syncNodes(null, testNode);
+        result = rendererNodesReader();
+        assertTrue(result.isEmpty());
+    }
+
+    // Remove Case
+
+    @Test
+    public void getNodeManagementIpByMountPointIid_absentNode() {
+        NodeId testNodeId = new NodeId(NODE_NAME);
+        InstanceIdentifier mountpointIid = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID)))
+                .child(Node.class, new NodeKey(testNodeId)).build();
+        String ipAddress = nodeManager.getNodeManagementIpByMountPointIid(mountpointIid);
+        assertNull(ipAddress);
+    }
+
+    @Test
+    public void getNodeManagementIpByMountPointIid_ipV4Case() throws Exception {
+        // Put node
+        Node testNode = createNode(Connected, IPv4_ADDRESS, NODE_NAME, Capabilities.Full);
+        InstanceIdentifier<Node> testNodeIid = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID)))
+                .child(Node.class, new NodeKey(testNode.getNodeId())).build();
+        ReadWriteTransaction rwt = dataBroker.newReadWriteTransaction();
+        rwt.put(LogicalDatastoreType.CONFIGURATION, testNodeIid, testNode, true);
+        rwt.submit().checkedGet();
+        InstanceIdentifier mountpointIid = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID)))
+                .child(Node.class, new NodeKey(NODE_NAME)).build();
+        String result = nodeManager.getNodeManagementIpByMountPointIid(mountpointIid);
+        assertEquals(IPv4_ADDRESS.getValue(), result);
+    }
+
+    private Node createNode(final NetconfNodeConnectionStatus.ConnectionStatus connectionStatus,
+                            final Ipv4Address ipAddress,
+                            final NodeId nodeName,
+                            final Capabilities choice) {
+        AvailableCapabilities capabilities = null;
+        switch (choice) {
+            case None: {
+                capabilities = emptyCapabilities();
+                break;
+            }
+            case Partial: {
+                capabilities = partialCapabilities();
+                break;
+            }
+            case Full: {
+                capabilities = fullCapabilities();
+            }
+        }
+        // Netconf node
+        NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder();
+        netconfNodeBuilder.setConnectionStatus(connectionStatus)
+                .setAvailableCapabilities(capabilities)
+                .setHost(new Host(new IpAddress(ipAddress)));
+        // Node
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setNodeId(new NodeId(nodeName))
+                .setKey(new NodeKey(new NodeId(nodeName)))
+                .addAugmentation(NetconfNode.class, netconfNodeBuilder.build());
+        return nodeBuilder.build();
+    }
+
+    // Utility methods
+
+    private List<RendererNode> rendererNodesReader() throws Exception {
+        InstanceIdentifier<Renderers> renderersIid =
+                InstanceIdentifier.builder(Renderers.class).build();
+        ReadWriteTransaction rwt = dataBroker.newReadWriteTransaction();
+        CheckedFuture<Optional<Renderers>, ReadFailedException> submitFuture =
+                rwt.read(LogicalDatastoreType.OPERATIONAL, renderersIid);
+        Optional<Renderers> optionalRenderers = submitFuture.checkedGet();
+        if (optionalRenderers.isPresent()) {
+            Renderers renderers = optionalRenderers.get();
+            if (renderers != null && renderers.getRenderer() != null && !renderers.getRenderer().isEmpty()) {
+                RendererNodes writtenNodes = renderers.getRenderer().get(0).getRendererNodes();
+                if (writtenNodes != null) {
+                    return writtenNodes.getRendererNode();
+                }
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    private AvailableCapabilities emptyCapabilities() {
+        AvailableCapabilitiesBuilder availableCapabilitiesBuilder = new AvailableCapabilitiesBuilder();
+        return availableCapabilitiesBuilder.build();
+    }
+
+    private AvailableCapabilities partialCapabilities() {
+        final String c1 = "(urn:ios?revision=2016-03-08)ned";
+        final String c2 = "(http://tail-f.com/yang/common?revision=2015-05-22)tailf-common";
+        final String c3 = "(http://tail-f.com/yang/common?revision=2015-03-19)tailf-cli-extensions";
+        String[] capabilityList = {c1, c2, c3};
+        AvailableCapabilitiesBuilder availableCapabilitiesBuilder = new AvailableCapabilitiesBuilder();
+        availableCapabilitiesBuilder.setAvailableCapability(Arrays.asList(capabilityList));
+        return availableCapabilitiesBuilder.build();
+    }
+
+    private AvailableCapabilities fullCapabilities() {
+        final String c1 = "(urn:ios?revision=2016-03-08)ned";
+        final String c2 = "(http://tail-f.com/yang/common?revision=2015-05-22)tailf-common";
+        final String c3 = "(http://tail-f.com/yang/common?revision=2015-03-19)tailf-cli-extensions";
+        final String c4 = "(http://tail-f.com/yang/common?revision=2013-11-07)tailf-meta-extensions";
+        final String c5 = "(urn:ietf:params:xml:ns:yang:ietf-yang-types?revision=2013-07-15)ietf-yang-types";
+        final String c6 = "(urn:ietf:params:xml:ns:yang:ietf-inet-types?revision=2013-07-15)ietf-inet-types";
+        String[] capabilityList = {c1, c2, c3, c4, c5, c6};
+        AvailableCapabilitiesBuilder availableCapabilitiesBuilder = new AvailableCapabilitiesBuilder();
+        availableCapabilitiesBuilder.setAvailableCapability(Arrays.asList(capabilityList));
+        return availableCapabilitiesBuilder.build();
+    }
+
+    private enum Capabilities {None, Partial, Full}
+}
\ No newline at end of file
diff --git a/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/PolicyManagerImplTest.java b/renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/manager/PolicyManagerImplTest.java
new file mode 100644 (file)
index 0000000..2ed3dc0
--- /dev/null
@@ -0,0 +1,399 @@
+package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.RendererPolicyUtil;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.ServiceChainingUtil;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriter;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfpName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathKey;
+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.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.rule.group.with.renderer.endpoint.participation.RuleGroupWithRendererEndpointParticipation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.rule.group.with.renderer.endpoint.participation.RuleGroupWithRendererEndpointParticipationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.rule.group.with.renderer.endpoint.participation.RuleGroupWithRendererEndpointParticipationKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.ConfigurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.EndpointsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.RendererEndpointsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.RendererForwarding;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.RuleGroupsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocationKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointWithPolicyKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.actions.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.ClassifierBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRuleBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.AddressEndpointWithLocationAug;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.AddressEndpointWithLocationAugBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+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.NodeId;
+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.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction.Out;
+import static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.EndpointPolicyParticipation.PROVIDER;
+import static org.powermock.api.support.membermodification.MemberMatcher.method;
+import static org.powermock.api.support.membermodification.MemberModifier.stub;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({RendererPolicyUtil.class, PolicyManagerUtil.class, SfcProviderServiceForwarderAPI.class})
+public class PolicyManagerImplTest {
+
+    private final String address = "address";
+    private final String connector = "connector";
+    private final SfpName servicePath = new SfpName("service-path");
+    private final RspName renderedPath = new RspName("rendered-path");
+    private final SffName forwarderName = new SffName("service-forwarder");
+    private final ContextId contextId_1 = new ContextId("context-id-1");
+    private final ContextId contextId_2 = new ContextId("context-id-2");
+    private final ContextId contextId_3 = new ContextId("context-id-3");
+    private final ContextId contextId_4 = new ContextId("context-id-4");
+    private final ContractId contractId = new ContractId("contract-id");
+    private final String ipAddress = "192.168.50.1";
+    private final NodeId nodeId = new NodeId("node-id");
+    private final SubjectName subjectName = new SubjectName("subject-name");
+    private final TenantId tenantId = new TenantId("tenant-id");
+    private final TopologyId topologyId = new TopologyId("topology-id");
+    private final ActionDefinitionId chainActionDefinitionId = new ActionDefinitionId("Action-Chain");
+    private final ActionDefinitionId otherActionDefinitionId = new ActionDefinitionId("Action-Other");
+    private final SfName functionName = new SfName("service-function");
+    private PolicyManagerImpl policyManager;
+    private DataBroker mountpoint;
+    private NodeManager nodeManager;
+    private WriteTransaction writeTransaction;
+
+    @Before
+    public void init() {
+        mountpoint = mock(DataBroker.class);
+        writeTransaction = mock(WriteTransaction.class);
+        nodeManager = mock(NodeManager.class);
+        policyManager = new PolicyManagerImpl(mountpoint, nodeManager);
+        when(mountpoint.newWriteOnlyTransaction()).thenReturn(writeTransaction);
+    }
+
+    @Test
+    public void testSyncPolicy_emptyConfiguration() throws Exception {
+        Configuration policyConfiguration = createTestConfiguration(null, null, null, null);
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    @Test
+    public void testSyncPolicy_noEndpointsInConfiguration() throws Exception {
+        RendererEndpoint rendererEndpoint = createRendererEndpoint(contextId_1, contextId_2, null);
+        Configuration policyConfiguration = createTestConfiguration(null, Collections.singletonList(rendererEndpoint),
+                null, null);
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    @Test
+    public void testSyncPolicy_noMountPoint() throws Exception {
+        AddressEndpointWithLocation endpointWithLocation = createAddressEndpointWithLocation(contextId_1, null, false);
+        RendererEndpoint rendererEndpoint = createRendererEndpoint(contextId_2, contextId_3, null);
+        Configuration policyConfiguration = createTestConfiguration(Collections.singletonList(endpointWithLocation),
+                Collections.singletonList(rendererEndpoint), null, null);
+
+        AbsoluteLocation location = createAbsoluteLocationExternal(connector, createMountpointIid());
+        AddressEndpointWithLocation lookupEndpoint = createAddressEndpointWithLocation(contextId_4, location, false);
+        stub(method(RendererPolicyUtil.class, "lookupEndpoint")).toReturn(lookupEndpoint);
+        when(nodeManager.getNodeMountPoint(eq(createMountpointIid()))).thenReturn(null);
+
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    @Test
+    public void testSyncPolicy_nullSgtTags() throws Exception {
+        AddressEndpointWithLocation endpointWithLocation = createAddressEndpointWithLocation(contextId_1, null, false);
+        RendererEndpoint rendererEndpoint = createRendererEndpoint(contextId_2, contextId_3, null);
+        Configuration policyConfiguration = createTestConfiguration(Collections.singletonList(endpointWithLocation),
+                Collections.singletonList(rendererEndpoint), null, null);
+
+        AbsoluteLocation location = createAbsoluteLocationExternal(connector, createMountpointIid());
+        AddressEndpointWithLocation lookupEndpoint = createAddressEndpointWithLocation(contextId_4, location, false);
+        stub(method(RendererPolicyUtil.class, "lookupEndpoint")).toReturn(lookupEndpoint);
+        when(nodeManager.getNodeMountPoint(eq(createMountpointIid()))).thenReturn(mountpoint);
+        when(nodeManager.getNodeIdByMountpointIid(eq(createMountpointIid()))).thenReturn(nodeId);
+        when(nodeManager.getNodeManagementIpByMountPointIid(eq(createMountpointIid()))).thenReturn(ipAddress);
+
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    @Test
+    public void testSyncPolicy_emptyRuleGroup() throws Exception {
+        AddressEndpointWithLocation endpointWithLocation = createAddressEndpointWithLocation(contextId_1, null, false);
+        RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation =
+                createRuleGroupWithRendererEpParticipation(PROVIDER);
+        RendererEndpoint rendererEndpoint = createRendererEndpoint(contextId_2, contextId_3,
+                ruleGroupWithParticipation);
+        RuleGroup ruleGroup = createRuleGroup(null);
+        Configuration policyConfiguration = createTestConfiguration(Collections.singletonList(endpointWithLocation),
+                Collections.singletonList(rendererEndpoint), null, ruleGroup);
+
+        AbsoluteLocation location = createAbsoluteLocationExternal(connector, createMountpointIid());
+        AddressEndpointWithLocation lookupEndpoint = createAddressEndpointWithLocation(contextId_4, location, true);
+        stub(method(RendererPolicyUtil.class, "lookupEndpoint")).toReturn(lookupEndpoint);
+        when(nodeManager.getNodeMountPoint(eq(createMountpointIid()))).thenReturn(mountpoint);
+        when(nodeManager.getNodeIdByMountpointIid(eq(createMountpointIid()))).thenReturn(nodeId);
+        when(nodeManager.getNodeManagementIpByMountPointIid(eq(createMountpointIid()))).thenReturn(ipAddress);
+
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    @Test
+    public void testSyncPolicy_noActionDefinition() throws Exception {
+        AddressEndpointWithLocation endpointWithLocation = createAddressEndpointWithLocation(contextId_1, null, false);
+        RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation =
+                createRuleGroupWithRendererEpParticipation(PROVIDER);
+        RendererEndpoint rendererEndpoint = createRendererEndpoint(contextId_2, contextId_3,
+                ruleGroupWithParticipation);
+
+        RuleGroup ruleGroup = createRuleGroup(createRule(Out, null));
+        Configuration policyConfiguration = createTestConfiguration(Collections.singletonList(endpointWithLocation),
+                Collections.singletonList(rendererEndpoint), null, ruleGroup);
+
+        AbsoluteLocation location = createAbsoluteLocationExternal(connector, createMountpointIid());
+        AddressEndpointWithLocation lookupEndpoint = createAddressEndpointWithLocation(contextId_4, location, true);
+        stub(method(RendererPolicyUtil.class, "lookupEndpoint")).toReturn(lookupEndpoint);
+        when(nodeManager.getNodeMountPoint(eq(createMountpointIid()))).thenReturn(mountpoint);
+        when(nodeManager.getNodeIdByMountpointIid(eq(createMountpointIid()))).thenReturn(nodeId);
+        when(nodeManager.getNodeManagementIpByMountPointIid(eq(createMountpointIid()))).thenReturn(ipAddress);
+
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    @Test
+    public void testSyncPolicy_otherAction() throws Exception {
+        AddressEndpointWithLocation endpointWithLocation = createAddressEndpointWithLocation(contextId_1, null, false);
+        RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation =
+                createRuleGroupWithRendererEpParticipation(PROVIDER);
+        RendererEndpoint rendererEndpoint = createRendererEndpoint(contextId_2, contextId_3,
+                ruleGroupWithParticipation);
+
+        RuleGroup ruleGroup = createRuleGroup(createRule(Out, otherActionDefinitionId));
+        Configuration policyConfiguration = createTestConfiguration(Collections.singletonList(endpointWithLocation),
+                Collections.singletonList(rendererEndpoint), null, ruleGroup);
+
+        AbsoluteLocation location = createAbsoluteLocationExternal(connector, createMountpointIid());
+        AddressEndpointWithLocation lookupEndpoint = createAddressEndpointWithLocation(contextId_4, location, true);
+        stub(method(RendererPolicyUtil.class, "lookupEndpoint")).toReturn(lookupEndpoint);
+        when(nodeManager.getNodeMountPoint(eq(createMountpointIid()))).thenReturn(mountpoint);
+        when(nodeManager.getNodeIdByMountpointIid(eq(createMountpointIid()))).thenReturn(nodeId);
+        when(nodeManager.getNodeManagementIpByMountPointIid(eq(createMountpointIid()))).thenReturn(ipAddress);
+
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    @Test
+    public void testSyncPolicy_asymmetricChain() throws Exception {
+        AddressEndpointWithLocation endpointWithLocation = createAddressEndpointWithLocation(contextId_1, null, false);
+        RuleGroupWithRendererEndpointParticipation ruleGroupWithParticipation =
+                createRuleGroupWithRendererEpParticipation(PROVIDER);
+        RendererEndpoint rendererEndpoint = createRendererEndpoint(contextId_2, contextId_3,
+                ruleGroupWithParticipation);
+
+        RuleGroup ruleGroup = createRuleGroup(createRule(Out, chainActionDefinitionId));
+        Configuration policyConfiguration = createTestConfiguration(Collections.singletonList(endpointWithLocation),
+                Collections.singletonList(rendererEndpoint), null, ruleGroup);
+
+        AbsoluteLocation location = createAbsoluteLocationExternal(connector, createMountpointIid());
+        AddressEndpointWithLocation lookupEndpoint = createAddressEndpointWithLocation(contextId_4, location, true);
+        stub(method(RendererPolicyUtil.class, "lookupEndpoint")).toReturn(lookupEndpoint);
+        when(nodeManager.getNodeMountPoint(eq(createMountpointIid()))).thenReturn(mountpoint);
+        when(nodeManager.getNodeIdByMountpointIid(eq(createMountpointIid()))).thenReturn(nodeId);
+        when(nodeManager.getNodeManagementIpByMountPointIid(eq(createMountpointIid()))).thenReturn(ipAddress);
+        ServiceFunctionPath sfp = createServiceFunctionPath();
+        stub(method(ServiceChainingUtil.class, "getServicePath")).toReturn(sfp);
+        RenderedServicePath rsp = createRenderedServicePath();
+        stub(method(ServiceChainingUtil.class, "createRenderedPath")).toReturn(rsp);
+        ServiceFunctionForwarder serviceFunctionForwarder = createServiceForwarder();
+        stub(method(SfcProviderServiceForwarderAPI.class, "readServiceFunctionForwarder"))
+                .toReturn(serviceFunctionForwarder);
+
+        ListenableFuture result = policyManager.syncPolicy(policyConfiguration, null);
+        assertTrue((boolean) result.get());
+    }
+
+    private ServiceFunctionForwarder createServiceForwarder() {
+        ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder = new ServiceFunctionForwarderBuilder();
+        serviceFunctionForwarderBuilder.setName(new SffName(forwarderName))
+                .setKey(new ServiceFunctionForwarderKey(new SffName(forwarderName)))
+                .setIpMgmtAddress(new IpAddress(new Ipv4Address(ipAddress)));
+        return serviceFunctionForwarderBuilder.build();
+    }
+
+    // Utility methods
+
+    private InstanceIdentifier createMountpointIid() {
+        return InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(topologyId))
+                .child(Node.class, new NodeKey(nodeId)).build();
+    }
+
+    private ResolvedRule createRule(HasDirection.Direction direction, ActionDefinitionId actionDefinitionId) {
+        ResolvedRuleBuilder resolvedRuleBuilder = new ResolvedRuleBuilder();
+        ClassifierBuilder classifierBuilder = new ClassifierBuilder();
+        classifierBuilder.setDirection(direction);
+        ActionBuilder actionBuilder = new ActionBuilder();
+        actionBuilder.setActionDefinitionId(actionDefinitionId);
+        resolvedRuleBuilder.setClassifier(Collections.singletonList(classifierBuilder.build()))
+                .setAction(Collections.singletonList(actionBuilder.build()));
+        return resolvedRuleBuilder.build();
+    }
+
+    private RuleGroupWithRendererEndpointParticipation createRuleGroupWithRendererEpParticipation(final EndpointPolicyParticipation participation) {
+        RuleGroupWithRendererEndpointParticipationBuilder ruleGroupBuilder = new RuleGroupWithRendererEndpointParticipationBuilder();
+        ruleGroupBuilder.setKey(new RuleGroupWithRendererEndpointParticipationKey(contractId, participation, subjectName,
+                tenantId));
+        return ruleGroupBuilder.build();
+    }
+
+    private AbsoluteLocation createAbsoluteLocationExternal(String connector, InstanceIdentifier mountpoint) {
+        ExternalLocationCaseBuilder externalLocationCaseBuilder = new ExternalLocationCaseBuilder();
+        externalLocationCaseBuilder.setExternalNodeConnector(connector)
+                .setExternalNodeMountPoint(mountpoint);
+        AbsoluteLocationBuilder absoluteLocationBuilder = new AbsoluteLocationBuilder();
+        absoluteLocationBuilder.setLocationType(externalLocationCaseBuilder.build());
+        return absoluteLocationBuilder.build();
+    }
+
+    private ServiceFunctionPath createServiceFunctionPath() {
+        ServiceFunctionPathBuilder serviceFunctionPathBuilder = new ServiceFunctionPathBuilder();
+        serviceFunctionPathBuilder.setKey(new ServiceFunctionPathKey(servicePath))
+                .setSymmetric(false);
+        return serviceFunctionPathBuilder.build();
+    }
+
+    private RenderedServicePath createRenderedServicePath() {
+        RenderedServicePathHopBuilder renderedServicePathHopBuilder = new RenderedServicePathHopBuilder();
+        renderedServicePathHopBuilder.setServiceFunctionForwarder(forwarderName);
+        renderedServicePathHopBuilder.setServiceFunctionName(functionName);
+        renderedServicePathHopBuilder.build();
+
+        RenderedServicePathBuilder renderedServicePathBuilder = new RenderedServicePathBuilder();
+        renderedServicePathBuilder.setKey(new RenderedServicePathKey(renderedPath))
+                .setRenderedServicePathHop(Collections.singletonList(renderedServicePathHopBuilder.build()));
+        return renderedServicePathBuilder.build();
+    }
+
+
+    private AddressEndpointWithLocation createAddressEndpointWithLocation(final ContextId contextId,
+                                                                          final AbsoluteLocation location,
+                                                                          boolean augmentation) {
+        AddressEndpointWithLocationAugBuilder augmentationBuilder = new AddressEndpointWithLocationAugBuilder();
+        augmentationBuilder.setSgt(new Sgt(1));
+        AddressEndpointWithLocationBuilder addressEndpointBuilder = new AddressEndpointWithLocationBuilder();
+        addressEndpointBuilder.setKey(new AddressEndpointWithLocationKey(address, IpPrefixType.class,
+                contextId, L2BridgeDomain.class))
+                .setAbsoluteLocation(location);
+        if (augmentation) {
+            addressEndpointBuilder.addAugmentation(AddressEndpointWithLocationAug.class, augmentationBuilder.build());
+        }
+        return addressEndpointBuilder.build();
+    }
+
+    private RendererEndpoint createRendererEndpoint(ContextId contextId_1, ContextId contextId_2,
+                                                    RuleGroupWithRendererEndpointParticipation ruleGroup) {
+        PeerEndpointWithPolicyBuilder peerEndpointWithPolicyBuilder = new PeerEndpointWithPolicyBuilder();
+        peerEndpointWithPolicyBuilder.setKey(new PeerEndpointWithPolicyKey(address, IpPrefixType.class, contextId_1,
+                L2BridgeDomain.class))
+                .setRuleGroupWithRendererEndpointParticipation(Collections.singletonList(ruleGroup));
+        RendererEndpointBuilder rendererEndpointBuilder = new RendererEndpointBuilder();
+        rendererEndpointBuilder.setKey(new RendererEndpointKey(address, IpPrefixType.class, contextId_2,
+                L2BridgeDomain.class))
+                .setPeerEndpointWithPolicy(Collections.singletonList(peerEndpointWithPolicyBuilder.build()));
+        return rendererEndpointBuilder.build();
+    }
+
+    private RuleGroup createRuleGroup(ResolvedRule rule) {
+        RuleGroupBuilder ruleGroupBuilder = new RuleGroupBuilder();
+        ruleGroupBuilder.setKey(new RuleGroupKey(contractId, subjectName, tenantId))
+                .setResolvedRule(Collections.singletonList(rule));
+        return ruleGroupBuilder.build();
+    }
+
+    private Configuration createTestConfiguration(final List<AddressEndpointWithLocation> endpointsWithLocation,
+                                                  final List<RendererEndpoint> rendererEndpoints,
+                                                  final RendererForwarding rendererForwarding,
+                                                  final RuleGroup ruleGroup) {
+        // Set endpoints
+        EndpointsBuilder endpointsBuilder = new EndpointsBuilder();
+        endpointsBuilder.setAddressEndpointWithLocation(endpointsWithLocation);
+        // Set renderer endpoints
+        RendererEndpointsBuilder rendererEndpointsBuilder = new RendererEndpointsBuilder();
+        rendererEndpointsBuilder.setRendererEndpoint(rendererEndpoints);
+        // Set rule group
+        RuleGroupsBuilder ruleGroupsBuilder = new RuleGroupsBuilder();
+        ruleGroupsBuilder.setRuleGroup(Collections.singletonList(ruleGroup));
+        // Build configuration
+        ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setEndpoints(endpointsBuilder.build())
+                .setRendererEndpoints(rendererEndpointsBuilder.build())
+                .setRendererForwarding(rendererForwarding)
+                .setRuleGroups(ruleGroupsBuilder.build());
+        return configurationBuilder.build();
+    }
+
+
+}
\ No newline at end of file
index 810a3f12d82a3a2d51fd10a5e0fdcaa1de1e84e6..af067b529ce388664c6165b596c2c7e2db77ffc9 100644 (file)
@@ -24,6 +24,7 @@ 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.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NodeWriter;
 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;
index b189656dbc2aeac982a4f162ea95d85b40e65170..fba4c12a67e2b2d07911d59f3d1fb79e99344c64 100644 (file)
@@ -34,12 +34,15 @@ import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev1407
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsBuilder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValueBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
+import static org.junit.Assert.assertNotNull;
+
 /**
  * Test for {@link PolicyManagerUtil}.
  */
@@ -65,6 +68,12 @@ public class PolicyManagerUtilTest {
         new OpendaylightSfc().setDataProvider(dataBroker);
     }
 
+    @Test
+    public void testCreateClassMap() {
+        ClassMap cm = PolicyManagerUtil.createClassMap("testName", null);
+        assertNotNull(cm);
+    }
+
     @Test
     public void testGetServicePath() throws Exception {
         final ParameterValue paramValueSfc = new ParameterValueBuilder()
@@ -80,7 +89,7 @@ public class PolicyManagerUtilTest {
         Mockito.when(roTx.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(ServiceFunctionPaths.class)))
                 .thenReturn(Futures.immediateCheckedFuture(Optional.of(sfPaths)));
 
-        final ServiceFunctionPath servicePath = PolicyManagerUtil.getServicePath(Collections.singletonList(paramValueSfc));
+        final ServiceFunctionPath servicePath = ServiceChainingUtil.getServicePath(Collections.singletonList(paramValueSfc));
         Assert.assertEquals(serviceFunctionPath, servicePath);
     }
 
@@ -93,7 +102,7 @@ public class PolicyManagerUtilTest {
         Mockito.when(roTx.read(Matchers.eq(LogicalDatastoreType.OPERATIONAL), rendererServicePathIICaptor.capture()))
                 .thenReturn(Futures.immediateCheckedFuture(Optional.of(renderedSP)));
 
-        final RenderedServicePath renderedPath = PolicyManagerUtil.createRenderedPath(serviceFunctionPath, tenantId);
+        final RenderedServicePath renderedPath = ServiceChainingUtil.createRenderedPath(serviceFunctionPath, tenantId);
         Assert.assertEquals(renderedSP, renderedPath);
         final InstanceIdentifier<RenderedServicePath> ii = rendererServicePathIICaptor.getValue();
         Assert.assertEquals("sfp-name-01tenant-id-01-gbp-rsp", ii.firstKeyOf(RenderedServicePath.class).getName().getValue());
@@ -109,7 +118,7 @@ public class PolicyManagerUtilTest {
                 .thenReturn(Futures.immediateCheckedFuture(Optional.of(renderedServicePath)));
 
 
-        final RenderedServicePath symmetricRenderedPath = PolicyManagerUtil.createSymmetricRenderedPath(
+        final RenderedServicePath symmetricRenderedPath = ServiceChainingUtil.createSymmetricRenderedPath(
                 serviceFunctionPath, renderedServicePath, tenantId);
         Assert.assertEquals(renderedServicePath, symmetricRenderedPath);
         final InstanceIdentifier<RenderedServicePath> ii = rendererServicePathIICaptor.getValue();