ios-xe renderer now creates configuration per endpoint pair
[groupbasedpolicy.git] / renderers / ios-xe / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ios_xe_provider / impl / util / ServiceChainingUtil.java
index a83e5931b0edae87bac27de32adba3378da48cd1..c099b39638f58bf6fde062295123fd31d4d951b5 100644 (file)
@@ -8,18 +8,50 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.ActionCase;
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.ActionInDirection;
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.createClassMap;
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.createPolicyMapEntry;
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.createSecurityGroupMatch;
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.generateClassMapName;
+import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil.getTenantId;
+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 javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
 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.PolicyConfigurationContext;
 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.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NetconfTransactionCreator;
+import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriterUtil;
 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.rsp.manager.rev160421.RendererPathStates;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathState;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.RendererPathStateKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.ConfiguredRenderedPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.rsp.manager.rev160421.renderer.path.states.renderer.path.state.configured.rendered.paths.ConfiguredRenderedPathKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RendererName;
 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;
@@ -27,20 +59,25 @@ import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev1407
 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.forwarder.base.SffDataPlaneLocator;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocator;
 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.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.LocatorType;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 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.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.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.ServiceFfName;
 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;
@@ -48,27 +85,218 @@ import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.serv
 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.RuleName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
 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.renderer.rev151103.EndpointPolicyParticipation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.unconfigured.rule.groups.unconfigured.rule.group.UnconfiguredResolvedRuleBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpoint;
 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);
+    private static final String RSP_SUFFIX = "-gbp-rsp";
+    private static final String RSP_REVERSED_SUFFIX = "-gbp-rsp-Reverse";
+    private static long timeout = 5000L;
+
+    /**
+     * According to provided action, this method gets service function path and collects all info about participation
+     * and orientation of path. According to path symmetricity, participation and direction, one of these cases happens:
+     * 1. Path is asymmetric, and it starts in  this classifier (specified by context) - direct chain is created
+     * 2. Path is asymmetric, and it starts in classifier on opposite side of the chain - skipped
+     * 3. Path is symmetric, and it starts in this classifier - direct chain is created
+     * 2. Path is symmetric, and it starts in classifier on opposite side of the chain - reversed path is created
+     * <p>
+     * Behaviour is correct also in case when "this" and "opposite" classifier is the same
+     *
+     * @param peerEndpoint   - peer endpoint, used to generate status and access to tenant ID
+     * @param sourceSgt      - security group tag of source endpoint
+     * @param destinationSgt - security group tag of destination endpoint
+     * @param actionMap      - contains all info to evaluate correct chain orientation according to endpoint participation
+     * @param context        - contains policy-map location and status info
+     * @param dataBroker     - to access odl datastore
+     */
+    static void newChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt,
+                               final Sgt destinationSgt, final Map<PolicyManagerImpl.ActionCase, ActionInDirection> actionMap,
+                               final PolicyConfigurationContext context, final DataBroker dataBroker) {
+        final ActionInDirection actionInDirection = actionMap.get(ActionCase.CHAIN);
+        if (actionInDirection == null) {
+            return;
+        }
+        context.setCurrentUnconfiguredRule(new UnconfiguredResolvedRuleBuilder()
+                .setRuleName(new RuleName(actionInDirection.getRuleName())).build());
+        // Rule action + orientation
+        final Action action = actionInDirection.getAction();
+        final EndpointPolicyParticipation participation = actionInDirection.getParticipation();
+        final Direction direction = actionInDirection.getDirection();
+        // Get service function path
+        final ServiceFunctionPath servicePath = ServiceChainingUtil.findServicePathFromParameterValues(action.getParameterValue());
+        if (servicePath == null || servicePath.getName() == null) {
+            final String info = String.format("service-path not found (sourceSgt=%s, destinationSgt=%s)",
+                    sourceSgt, destinationSgt);
+            context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
+            return;
+        }
+        final TenantId tenantId = PolicyManagerUtil.getTenantId(peerEndpoint);
+        if (tenantId == null) {
+            final String info = String.format("tenant-id not found (sourceSgt=%s, destinationSgt=%s)",
+                    sourceSgt, destinationSgt);
+            context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
+            return;
+        }
+        boolean sfcPartSuccessful = true;
+        // Creates direct path in corresponding direction
+        if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
+                (participation.equals(CONSUMER) && direction.equals(In))) {
+            final RenderedServicePath renderedServicePath = ServiceChainingUtil.resolveRenderedServicePath(servicePath,
+                    tenantId, dataBroker, sourceSgt, destinationSgt, context);
+            sfcPartSuccessful = resolveRemoteSfcComponents(renderedServicePath, context);
+            // Creates reversed path if symmetric
+        } else if (servicePath.isSymmetric()) {
+            final RenderedServicePath renderedServicePath =
+                    ServiceChainingUtil.resolveReversedRenderedServicePath(servicePath, tenantId, dataBroker, sourceSgt,
+                            destinationSgt, context);
+            sfcPartSuccessful = resolveRemoteSfcComponents(renderedServicePath, context);
+        }
+        if (!sfcPartSuccessful) {
+            final String info = String.format("failed during sfc-part execution (sourceSgt=%s, destinationSgt=%s)",
+                    sourceSgt, destinationSgt);
+            context.appendUnconfiguredRendererEP(StatusUtil.assembleNotConfigurableRendererEPForPeer(context,
+                    peerEndpoint, info));
+        }
+    }
+
+    /**
+     * According to service function path and direction, creates appropriate rendered service path name {@link RspName}
+     * and starts appropriate method which removes policy for resolved endpoint pair
+     *
+     * @param peerEndpoint   - contains info about tenant ID
+     * @param sourceSgt      - security group tag of source endpoint
+     * @param destinationSgt - security group tag of destination endpoint
+     * @param actionMap      - contains all info to evaluate correct chain orientation according to endpoint participation
+     * @param context        - contains policy-map location and status info
+     */
+    static void resolveRemovedChainAction(final PeerEndpoint peerEndpoint, final Sgt sourceSgt, final Sgt destinationSgt,
+                                          final Map<ActionCase, ActionInDirection> actionMap, final PolicyConfigurationContext context) {
+        final ActionInDirection actionInDirection = actionMap.get(ActionCase.CHAIN);
+        final Action action = actionInDirection.getAction();
+        final EndpointPolicyParticipation participation = actionInDirection.getParticipation();
+        final Direction direction = actionInDirection.getDirection();
+        final ServiceFunctionPath servicePath = ServiceChainingUtil.findServicePathFromParameterValues(action.getParameterValue());
+        if (servicePath == null || servicePath.getName() == null) {
+            return;
+        }
+        final TenantId tenantId = getTenantId(peerEndpoint);
+        if (tenantId == null) {
+            return;
+        }
+        //Symmetric chain
+        if ((participation.equals(PROVIDER) && direction.equals(Out)) ||
+                (participation.equals(CONSUMER) && direction.equals(In))) {
+            final RspName rspName = generateRspName(servicePath, tenantId);
+            resolveRemovedRenderedServicePath(rspName, sourceSgt, destinationSgt, context);
+
+        } else if (servicePath.isSymmetric()) {
+            final RspName rspName = generateReversedRspName(servicePath, tenantId);
+            resolveRemovedRenderedServicePath(rspName, sourceSgt, destinationSgt, context);
+        }
+    }
+
+    /**
+     * Service-path (netconf) is created on every netconf device, which contains service function belonging to specific
+     * chain. Classifier has to be able to reach first service function forwarder in order to send packet to chain. If
+     * first service function forwarder is present on the same node as classifier, service-path entry should be already
+     * present (created by IOS-XE renderer in SFC) also with appropriate remote SFF if necessary. If first SFF is on
+     * different node (remote classifier), classifier has to create it's own service-path entry with remote SFF.
+     *
+     * @param renderedServicePath - path classifier has to reach
+     * @param context             - contains policy-map location and status info
+     * @return true if everything went good, false otherwise
+     */
+    public static boolean resolveRemoteSfcComponents(final RenderedServicePath renderedServicePath,
+                                                      final PolicyConfigurationContext context) {
+        final PolicyManagerImpl.PolicyMapLocation location = context.getPolicyMapLocation();
+        final ServiceFunctionForwarder forwarder = getFirstHopSff(renderedServicePath);
+        if (forwarder == null) {
+            return false;
+        }
+        final SffName sffName = forwarder.getName();
+        if (forwarder.getSffDataPlaneLocator() == null || forwarder.getSffDataPlaneLocator().isEmpty()) {
+            LOG.warn("Service function forwarder {} does not contain data plane locator", sffName.getValue());
+            return false;
+        }
+        // TODO only first dpl resolved
+        final SffDataPlaneLocator sffDataPlaneLocator = forwarder.getSffDataPlaneLocator().get(0);
+        final DataPlaneLocator dataPlaneLocator = sffDataPlaneLocator.getDataPlaneLocator();
+        final LocatorType locatorType = dataPlaneLocator.getLocatorType();
+        if (locatorType != null && locatorType instanceof Ip) {
+            final IpAddress remoteForwarderIpAddress = (((Ip) locatorType).getIp());
+            if (remoteForwarderIpAddress == null || remoteForwarderIpAddress.getIpv4Address() == null) {
+                LOG.warn("Service function forwarder {} data plane locator does not contain ip address", sffName.getValue());
+                return false;
+            }
+            final String remoteForwarderStringIp = remoteForwarderIpAddress.getIpv4Address().getValue();
+            final java.util.Optional<IpAddress> optionalIpMgmtAddress = java.util.Optional.ofNullable(forwarder.getIpMgmtAddress());
 
-    static ServiceFunctionPath getServicePath(final List<ParameterValue> params) {
+            return optionalIpMgmtAddress.map(IpAddress::getIpv4Address)
+                    .map(Ipv4Address::getValue)
+                    .map(addressValue -> {
+                        final ServiceTypeChoice serviceTypeChoice;
+                        if (!addressValue.equals(location.getManagementIpAddress())) {
+                            // Remote forwarder
+                            final ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
+                            remoteSffBuilder.setName(sffName.getValue())
+                                    .setKey(new ServiceFfNameKey(sffName.getValue()))
+                                    .setIp(new IpBuilder().setAddress(new Ipv4Address(remoteForwarderStringIp)).build());
+                            boolean rsResult = PolicyWriterUtil.writeRemote(remoteSffBuilder.build(), location);
+                            context.setFutureResult(Futures.immediateCheckedFuture(rsResult));
+                            serviceTypeChoice = createForwarderTypeChoice(sffName.getValue());
+                            // Service chain
+                            final List<Services> services = new ArrayList<>();
+                            final ServicesBuilder servicesBuilder = new ServicesBuilder();
+                            servicesBuilder.setServiceIndexId(renderedServicePath.getStartingIndex())
+                                    .setServiceTypeChoice(serviceTypeChoice);
+                            services.add(servicesBuilder.build());
+                            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();
+                            boolean scResult = PolicyWriterUtil.writeServicePath(serviceChain, location);
+                            context.setFutureResult(Futures.immediateCheckedFuture(scResult));
+                        }
+                        return true;
+                    }).orElseGet(createNegativePathWithLogSupplier(sffName.getValue(),
+                            (value) -> LOG.error("Cannot create remote forwarder, SFF {} does not contain management ip address",
+                                    value))
+                    );
+        }
+        return false;
+    }
+
+    /**
+     * Investigates provided parameter values and derives service chain name. This name is used to find service function
+     * path
+     *
+     * @param params - list of parameters
+     * @return - service function path if found, null if provided parameters does not correspond with any chain or there
+     * is no service function path defined by that chain
+     */
+    @Nullable
+    static ServiceFunctionPath findServicePathFromParameterValues(final List<ParameterValue> params) {
         if (params == null || params.isEmpty()) {
             LOG.error("Cannot found service path, parameter value is null");
             return null;
@@ -93,7 +321,7 @@ public class ServiceChainingUtil {
             LOG.error("Cannot found service path, chain name is null");
             return null;
         }
-        final ServiceFunctionPath serviceFunctionPath = findServiceFunctionPath(new SfcName(chainName));
+        final ServiceFunctionPath serviceFunctionPath = findServiceFunctionPathFromServiceChainName(new SfcName(chainName));
         if (serviceFunctionPath == null) {
             LOG.error("Service function path not found for name {}", chainName);
             return null;
@@ -101,213 +329,266 @@ public class ServiceChainingUtil {
         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;
+    static ServiceFunctionPath findServiceFunctionPathFromServiceChainName(@Nonnull final SfcName chainName) {
+        final ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
+        if (allPaths == null || allPaths.getServiceFunctionPath() == null || allPaths.getServiceFunctionPath().isEmpty()) {
+            return null;
         }
-        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));
+        for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
+            if (chainName.equals(serviceFunctionPath.getServiceChainName())) {
+                return serviceFunctionPath;
+            }
         }
-        policyWriter.cache(entries);
+        return null;
     }
 
-    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;
+    /**
+     * Creates {@link RenderedServicePath} if not exist. If created, ios-xe renderer in SFC is invoked, so this method
+     * has to wait till SFC part is done to prevent transaction collisions in {@link this#checkRspManagerStatus(RspName,
+     * DataBroker)}. If this operation is successful, class-map {@link ClassMap} and entry in policy-map {@link Class}
+     * is written
+     *
+     * @param sfp            - path used to create RSP
+     * @param tenantId       - used to generate RSP name according to GBP standards
+     * @param dataBroker     - data provider to access odl controller
+     * @param sourceSgt      - source security group tag
+     * @param destinationSgt - destination security group tag
+     * @param context        - contains policy-map location and status info
+     * @return read/created RSP
+     */
+    static RenderedServicePath resolveRenderedServicePath(final ServiceFunctionPath sfp, final TenantId tenantId,
+                                                                  final DataBroker dataBroker, final Sgt sourceSgt, final Sgt destinationSgt,
+                                                                  final PolicyConfigurationContext context) {
+        // Get rendered service path
+        final RspName rspName = generateRspName(sfp, tenantId);
+        RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
+        if (renderedServicePath == null) {
+            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());
+            checkRspManagerStatus(rspName, dataBroker);
         }
-        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());
+        // Create class-map and policy-map entry
+        final String classMapName = generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
+        final Match match = createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
+        final ClassMap classMap = createClassMap(classMapName, match);
+        final Class policyMapEntry = createPolicyMapEntry(classMapName, renderedServicePath, ActionCase.CHAIN);
+        boolean cmResult = PolicyWriterUtil.writeClassMap(classMap, context.getPolicyMapLocation());
+        context.setFutureResult(Futures.immediateCheckedFuture(cmResult));
+        boolean pmeResult = PolicyWriterUtil.writePolicyMapEntry(policyMapEntry, context.getPolicyMapLocation());
+        context.setFutureResult(Futures.immediateCheckedFuture(pmeResult));
         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;
+    /**
+     * Creates reversed {@link RenderedServicePath} if not exist. To be successful, direct path has to exist.
+     * If created, ios-xe renderer in SFC is invoked, so this method has to wait till SFC part is done to prevent
+     * transaction collisions. If this operation is successful, class-map {@link ClassMap} and entry in policy-map
+     * {@link Class} is written
+     *
+     * @param sfp            - path used to create RSP
+     * @param tenantId       - used to generate RSP name according to GBP standards
+     * @param dataBroker     - data provider to access odl controller
+     * @param sourceSgt      - source security group tag
+     * @param destinationSgt - destination security group tag
+     * @param context        - contains policy-map location and status info
+     * @return read/created RSP
+     */
+    public static RenderedServicePath resolveReversedRenderedServicePath(final ServiceFunctionPath sfp, final TenantId tenantId,
+                                                                          final DataBroker dataBroker, final Sgt sourceSgt,
+                                                                          final Sgt destinationSgt, final PolicyConfigurationContext context) {
+        // Get rendered service path
+        final RspName rspName = generateRspName(sfp, tenantId);
+        RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
+        if (renderedServicePath == null) {
+            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());
+            checkRspManagerStatus(rspName, dataBroker);
+        }
+        // Get reversed rendered service path
+        final RspName reversedRspName = generateReversedRspName(sfp, tenantId);
+        RenderedServicePath reversedRenderedPath = SfcProviderRenderedPathAPI.readRenderedServicePath(reversedRspName);
+        if (reversedRenderedPath == null) {
+            LOG.info("Reversed rendered service path with name {} not found, creating a new one ..", reversedRspName.getValue());
+            reversedRenderedPath = SfcProviderRenderedPathAPI.createReverseRenderedServicePathEntry(renderedServicePath);
+            LOG.info("Rendered service path {} created", reversedRspName.getValue());
+            checkRspManagerStatus(reversedRspName, dataBroker);
         }
-        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());
+        // Create class-map and policy-map entry
+        final String classMapName = generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
+        final Match match = createSecurityGroupMatch(sourceSgt.getValue(), destinationSgt.getValue());
+        final ClassMap classMap = createClassMap(classMapName, match);
+        final Class policyMapEntry = createPolicyMapEntry(classMapName, renderedServicePath, ActionCase.CHAIN);
+        boolean cmResult = PolicyWriterUtil.writeClassMap(classMap, context.getPolicyMapLocation());
+        context.setFutureResult(Futures.immediateCheckedFuture(cmResult));
+        boolean pmeResult = PolicyWriterUtil.writePolicyMapEntry(policyMapEntry, context.getPolicyMapLocation());
+        context.setFutureResult(Futures.immediateCheckedFuture(pmeResult));
+        resolveRemoteSfcComponents(renderedServicePath, context);
         return reversedRenderedPath;
     }
 
     /**
-     * Method checks up, whether a {@link Local} Service Function Forwarder is present on device or not.
+     * Removes all policy setup created according to rendered service path.
      *
-     * @param mountpoint used to access specific device
-     * @return true if Local Forwarder is present, false otherwise
+     * @param rspName        - rendered service path name
+     * @param sourceSgt      - source security group tag
+     * @param destinationSgt - destination security group tag
+     * @param context        - context with policy-map location
      */
-    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());
+    private static void resolveRemovedRenderedServicePath(final RspName rspName, final Sgt sourceSgt, final Sgt destinationSgt,
+                                                          final PolicyConfigurationContext context) {
+        final String classMapName = PolicyManagerUtil.generateClassMapName(sourceSgt.getValue(), destinationSgt.getValue());
+        final ClassMap classMap = PolicyManagerUtil.createClassMap(classMapName, null);
+        final Class policyMapEntry = PolicyManagerUtil.createPolicyMapEntry(classMapName, null, PolicyManagerImpl.ActionCase.CHAIN);
+        PolicyWriterUtil.removePolicyMapEntry(policyMapEntry, context.getPolicyMapLocation());
+        PolicyWriterUtil.removeClassMap(classMap, context.getPolicyMapLocation());
+        final RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.readRenderedServicePath(rspName);
+        final ServiceFunctionForwarder firstHopSff = getFirstHopSff(renderedServicePath);
+        if (firstHopSff != null && firstHopSff.getIpMgmtAddress() != null &&
+                firstHopSff.getIpMgmtAddress().getIpv4Address() != null) {
+            final String sffMgmtIpValue = firstHopSff.getIpMgmtAddress().getIpv4Address().getValue();
+            if (!sffMgmtIpValue.equals(context.getPolicyMapLocation().getManagementIpAddress())) {
+                // Remove service chain and remote forwarder
+                final ServiceChain serviceChain = createServiceChain(renderedServicePath);
+                final ServiceFfName remoteForwarder = createRemoteForwarder(firstHopSff);
+                PolicyWriterUtil.removeServicePath(serviceChain, context.getPolicyMapLocation());
+                PolicyWriterUtil.removeRemote(remoteForwarder, context.getPolicyMapLocation());
+            }
         }
-        return false;
+    }
+
+    static ServiceFfName createRemoteForwarder(ServiceFunctionForwarder firstHopSff) {
+        final ServiceFfNameBuilder serviceFfNameBuilder = new ServiceFfNameBuilder();
+        serviceFfNameBuilder.setName(firstHopSff.getName().getValue());
+        return serviceFfNameBuilder.build();
+    }
+
+    private static ServiceTypeChoice createForwarderTypeChoice(final String forwarderName) {
+        final ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder();
+        sffBuilder.setServiceFunctionForwarder(forwarderName);
+        return sffBuilder.build();
     }
 
     /**
-     * Method checks up, if some {@link ServicePath} is present on device.
+     * Creates service-chain with name/key only, using rendered service path id. This object contains no data, it is used
+     * to create instance identifier when appropriate service-chain is removed from particular 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
+     * @param renderedServicePath - it's path id is used as a identifier
+     * @return service-chain object with id
      */
-    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 ServiceChain createServiceChain(final RenderedServicePath renderedServicePath) {
+        final Long pathId = renderedServicePath.getPathId();
+        final ServicePathBuilder servicePathBuilder = new ServicePathBuilder();
+        final ServiceChainBuilder serviceChainBuilder = new ServiceChainBuilder();
+        servicePathBuilder.setServicePathId(pathId)
+                .setKey(new ServicePathKey(pathId));
+        serviceChainBuilder.setServicePath(Collections.singletonList(servicePathBuilder.build()));
+        return serviceChainBuilder.build();
     }
 
-    private static ServiceFunctionPath findServiceFunctionPath(final SfcName chainName) {
-        final ServiceFunctionPaths allPaths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
-        for (ServiceFunctionPath serviceFunctionPath : allPaths.getServiceFunctionPath()) {
-            if (serviceFunctionPath.getServiceChainName().equals(chainName)) {
-                return serviceFunctionPath;
-            }
+    private static <T> Supplier<Boolean> createNegativePathWithLogSupplier(final T value, final Consumer<T> logCommand) {
+        return () -> {
+            // fireLog
+            logCommand.accept(value);
+            return false;
+        };
+    }
+
+    private static ServiceFunctionForwarder getFirstHopSff(RenderedServicePath renderedServicePath) {
+        if (renderedServicePath == null || renderedServicePath.getRenderedServicePathHop() == null ||
+                renderedServicePath.getRenderedServicePathHop().isEmpty()) {
+            return null;
         }
-        return null;
+        final RenderedServicePathHop firstHop = renderedServicePath.getRenderedServicePathHop().get(0);
+        final SffName firstHopSff = firstHop.getServiceFunctionForwarder();
+        if (firstHopSff == null) {
+            return null;
+        }
+        return SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(firstHopSff);
     }
 
-    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)
+    private static RspName generateRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
+        return new RspName(serviceFunctionPath.getName().getValue() + "-" + tenantId.getValue() + RSP_SUFFIX);
+    }
 
-            // Local case (only when does not exist)
+    private static RspName generateReversedRspName(final ServiceFunctionPath serviceFunctionPath, final TenantId tenantId) {
+        return new RspName(serviceFunctionPath.getName().getValue() + "-" + tenantId.getValue() + RSP_REVERSED_SUFFIX);
+    }
 
-            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());
+    private static void checkRspManagerStatus(final RspName rspName, final DataBroker dataBroker) {
+        // TODO A better way to do this is to register listener and wait for notification than using hardcoded timeout
+        // with Thread.sleep(). Example in class BridgeDomainManagerImpl
+        ConfiguredRenderedPath renderedPath = null;
+        LOG.debug("Waiting for SFC to configure path {} ...", rspName.getValue());
+
+        byte attempt = 0;
+        do {
+            attempt++;
+            // Wait
+            try {
+                Thread.sleep(timeout);
+            } catch (InterruptedException e) {
+                LOG.error("Thread interrupted while waiting ... {} ", e);
             }
-            // 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());
+            // Read actual status
+            final InstanceIdentifier<ConfiguredRenderedPath> statusIid = InstanceIdentifier.builder(RendererPathStates.class)
+                    .child(RendererPathState.class, new RendererPathStateKey(new RendererName("ios-xe-renderer")))
+                    .child(ConfiguredRenderedPaths.class)
+                    .child(ConfiguredRenderedPath.class, new ConfiguredRenderedPathKey(rspName)).build();
+            final java.util.Optional<ReadWriteTransaction> optionalTransaction =
+                    NetconfTransactionCreator.netconfReadWriteTransaction(dataBroker);
+            if (!optionalTransaction.isPresent()) {
+                LOG.warn("Failed to create transaction, mountpoint: {}", dataBroker);
                 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());
+            ReadWriteTransaction transaction = optionalTransaction.get();
+            try {
+                final CheckedFuture<Optional<ConfiguredRenderedPath>, ReadFailedException> submitFuture =
+                        transaction.read(LogicalDatastoreType.OPERATIONAL, statusIid);
+                final Optional<ConfiguredRenderedPath> optionalPath = submitFuture.checkedGet();
+                if (optionalPath.isPresent()) {
+                    renderedPath = optionalPath.get();
+                }
+            } catch (ReadFailedException e) {
+                LOG.warn("Failed while read rendered path status ... {} ", e.getMessage());
+            }
+            if (renderedPath == null || renderedPath.getPathStatus() == null ||
+                    renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.InProgress)) {
+                LOG.info("Still waiting for SFC ... ");
+            } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Failure)) {
+                LOG.warn("SFC failed to configure rsp");
+            } else if (renderedPath.getPathStatus().equals(ConfiguredRenderedPath.PathStatus.Success)) {
+                LOG.debug("RSP {} configured by SFC", rspName.getValue());
+                try {
+                    Thread.sleep(timeout); // Just for sure, maybe will be safe to remove this
+                } catch (InterruptedException e) {
+                    LOG.error("Thread interrupted while waiting ... {} ", e);
+                }
+                return;
             }
-
-            // 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);
         }
+        while (attempt <= 6);
+        LOG.warn("Maximum number of attempts reached");
     }
 
-    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();
+    /**
+     * Only for test purposes
+     *
+     * @param value - set actual timeout value
+     */
+    @VisibleForTesting
+    public static void setTimeout(long value) {
+        timeout = value;
     }
-
-}
+}
\ No newline at end of file