Fixed issues with registration point for renderers
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / sf / ChainAction.java
old mode 100644 (file)
new mode 100755 (executable)
index 44f6511..d043f26
@@ -1,5 +1,3 @@
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
-
 /*
  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
  *
@@ -8,252 +6,260 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc1RegAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.ChainActionFlows.createChainTunnelFlows;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNsiAction;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNspAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
 
-import java.math.BigInteger;
 import java.util.List;
 import java.util.Map;
 
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.sf.actions.ChainActionDefinition;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.PolicyPair;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcIidFactory;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader.SfcNshHeaderBuilder;
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
 import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI;
 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.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
 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.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
 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.rev100924.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+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.definitions.ActionDefinition;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
 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.tenants.tenant.subject.feature.instances.ActionInstance;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.action.definition.SupportedParameterValues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.action.definition.SupportedParameterValuesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
-import com.google.common.net.InetAddresses;
+import com.google.common.collect.Iterables;
 
 /**
  * Chain action for the OpenFlow Overlay renderer
  * TODO: separate the generic definition from the concrete
- * implementation for the OpenFlow Ovelray renderer
+ * implementation for the OpenFlow Overlay renderer
  */
 public class ChainAction extends Action {
 
     private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
 
-    public static final ActionDefinitionId ID = new ActionDefinitionId("3d886be7-059f-4c4f-bbef-0356bea40933");
-
-    public static final Integer CHAIN_CONDITION_GROUP = 0xfffffe;
-
-    protected static final String TYPE = "type";
-
-    // the chain action
-    public static final String SFC_CHAIN_ACTION = "chain";
-    // the parameter used for storing the chain name
-    public static final String SFC_CHAIN_NAME = "sfc-chain-name";
-
-    protected static final ActionDefinition DEF = new ActionDefinitionBuilder().setId(ID)
-        .setName(new ActionName(SFC_CHAIN_ACTION))
-        .setDescription(new Description("Send the traffic through a Service Function Chain"))
-        .setParameter(
-                (ImmutableList.of(new ParameterBuilder().setName(new ParameterName(SFC_CHAIN_NAME))
-                    .setDescription(new Description("The named chain to match against"))
-                    .setIsRequired(IsRequired.Required)
-                    .setType(Type.String)
-                    .build())))
-        .build();
-
     @Override
     public ActionDefinitionId getId() {
-        return ID;
+        return ChainActionDefinition.ID;
     }
 
     @Override
     public ActionDefinition getActionDef() {
-        return DEF;
+        return ChainActionDefinition.DEFINITION;
     }
 
     @Override
-    public List<ActionBuilder> updateAction(List<ActionBuilder> actions,
-                                            Map<String, Object> params,
-                                            Integer order,
-                                            NetworkElements netElements) {
+    public List<ActionBuilder> updateAction(List<ActionBuilder> actions, Map<String, Object> params, Integer order,
+            NetworkElements netElements, PolicyPair policyPair, OfWriter ofWriter, OfContext ctx, Direction direction) {
         /*
          * Get the named chain
          */
-        ServiceFunctionPath sfcPath = null;
         String chainName = null;
         if (params != null) {
-            LOG.debug("Searching for named chain");
+            LOG.debug("updateAction: Searching for named chain");
             for (String name : params.keySet()) {
                 if (name instanceof String) {
-                    if (name.equals(SFC_CHAIN_NAME)) {
+                    if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
                         chainName = (String) params.get(name);
                         if (chainName == null) {
-                            LOG.error("ChainAction: Chain name was null");
+                            LOG.error("updateAction: Chain name was null");
                             return null;
                         }
-                        sfcPath = getSfcPath(chainName);
                     }
                 }
             }
         } else {
-            LOG.error("ChainAction: Parameters null for chain action");
+            LOG.error("updateAction: Parameters null for chain action");
             return null;
         }
 
-        if (sfcPath == null) {
-            LOG.error("ChainAction: SFC Path null for chain {}", chainName);
+        if (chainName == null) {
+            LOG.error("updateAction: Chain name was null");
             return null;
         }
-        String rspName = sfcPath.getName() + "-gbp-rsp";
-        RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName);
-        if (rspFirstHop == null) {
-            LOG.info("ChainAction: Could not find RSP {} for Chain {}", rspName, chainName);
 
-            CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder().setParentServiceFunctionPath(
-                    sfcPath.getName())
-                .setName(rspName)
-                .setSymmetric(Boolean.FALSE)
-                .build();
-            RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(
-                    sfcPath, rspInput);
-            if (renderedServicePath == null) {
-                LOG.error("Could not find or create RSP for chain {}", chainName);
+        /*
+         * If path is symmetrical then there are two RSPs.
+         * if srcEp is in consumer EPG use "rspName"
+         * else srcEp is in provider EPG, "rspName-Reverse".
+         */
+        ServiceFunctionPath sfcPath = getSfcPath(new SfcName(chainName));
+        if (sfcPath == null || sfcPath.getName() == null) {
+            LOG.error("updateAction: SFC Path was invalid. Either null or name was null.", sfcPath);
+            return null;
+        }
+        // Find existing RSP based on following naming convention, else create it.
+        RspName rspName = new RspName(sfcPath.getName() + "-gbp-rsp");
+        ReadOnlyTransaction rTx = ctx.getDataBroker().newReadOnlyTransaction();
+        RenderedServicePath renderedServicePath;
+        RenderedServicePath rsp = getRspByName(rspName, rTx);
+        if (rsp == null) {
+            renderedServicePath = createRsp(sfcPath, rspName);
+            if (renderedServicePath != null) {
+                LOG.info("updateAction: Could not find RSP {} for Chain {}, created.", rspName, chainName);
+            } else {
+                LOG.error("updateAction: Could not create RSP {} for Chain {}", rspName, chainName);
                 return null;
             }
-            rspFirstHop=SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(renderedServicePath.getName());
+        } else {
+            renderedServicePath = rsp;
         }
 
-        IpAddress sfcTunIpDst = rspFirstHop.getIp();
-        sfcTunIpDst.getIpv4Address();
-        if (sfcTunIpDst == null || sfcTunIpDst.getIpv4Address() == null || sfcTunIpDst.getIpv6Address() != null) {
-            LOG.error("Invalid IP Tunnel destination for SFC RSP First Hop {}", rspName);
-            return null;
-        }
-        PortNumber sfcTunUdpPort = rspFirstHop.getPort();
-        if (sfcTunUdpPort == null) {
-            LOG.error("Invalid UDP Port Number for SFC RSP {}", rspName);
-            return null;
-        }
-        Long sfcNsp = rspFirstHop.getPathId();
-        if (sfcNsp == null) {
-            LOG.error("Invalid NSP for SFC RSP {}", rspName);
+        try {
+            if (sfcPath.isSymmetric() && direction.equals(Direction.Out)){
+                rspName = new RspName(rspName.getValue() + "-Reverse");
+                rsp = getRspByName(rspName, rTx);
+                if (rsp == null) {
+                    LOG.info("updateAction: Could not find Reverse RSP {} for Chain {}", rspName, chainName);
+                    renderedServicePath = createSymmetricRsp(renderedServicePath);
+                    if (renderedServicePath == null) {
+                        LOG.error("updateAction: Could not create RSP {} for Chain {}", rspName, chainName);
+                        return null;
+                    }
+                } else {
+                    renderedServicePath = rsp;
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("updateAction: Attemping to determine if srcEp {} was consumer.", netElements.getSrcEp().getKey(), e);
             return null;
         }
-        Short sfcNsi = rspFirstHop.getStartingIndex();
-        if (sfcNsi == null) {
-            LOG.error("Invalid NSI for SFC RSP {}", rspName);
+
+        RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName);
+        if (!isValidRspFirstHop(rspFirstHop)) {
+            // Errors logged in method.
             return null;
         }
 
-        NodeConnectorId tunOpenFlowPort = SwitchManager.getTunnelPort(netElements.getNodeId(), TunnelTypeVxlan.class);
+        NodeId tunnelDestNodeId=netElements.getDstNodeId();
 
-        /*
-         * Setting NSH Network Context Headers for post-SFC encapsulation
-         * VXLAN header encap:
-         * - TunnelDestination IP: NSH C1
-         * - Tunnel ID (VNID) NSH C2
-         */
-        long postSfcTunnelDst = 999L;
-        IpAddress tunnelDest;
+        Long returnVnid = (long) netElements.getSrcEpOrds().getTunnelId();
 
-        if (netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId().equals(netElements.getNodeId())) {
-            // Return destination is here
-            tunnelDest=SwitchManager.getTunnelIP(netElements.getNodeId(), TunnelTypeVxlan.class);
-        } else {
-            tunnelDest=SwitchManager.getTunnelIP(netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId(), TunnelTypeVxlan.class);
+        IpAddress tunnelDest = ctx.getSwitchManager().getTunnelIP(tunnelDestNodeId, TunnelTypeVxlanGpe.class);
+        if (tunnelDest == null || tunnelDest.getIpv4Address() == null) {
+            LOG.error("updateAction: Invalid tunnelDest for NodeId: {}", tunnelDestNodeId);
+            return null;
         }
-        postSfcTunnelDst = (InetAddresses.coerceToInteger(InetAddresses.forString(tunnelDest.getIpv4Address().getValue()))) & 0xFFFFFFFFL;
 
-        // TunnelDestination after Chain
-        actions = addActionBuilder(actions, nxLoadNshc1RegAction(postSfcTunnelDst), order++);
-        // VNID after Chain
-        actions = addActionBuilder(actions, nxLoadNshc2RegAction((long) netElements.getSrcOrds().getTunnelId()), order++);
-
-        /*
-         * Set the tunnel destination IP
-         */
-        if (sfcTunIpDst.getIpv4Address() != null) {
-            String nextHop = sfcTunIpDst.getIpv4Address().getValue();
-            actions = addActionBuilder(actions, nxLoadTunIPv4Action(nextHop, false), order);
-        } else if (sfcTunIpDst.getIpv6Address() != null) {
-            LOG.error("IPv6 tunnel destination {} not supported", sfcTunIpDst.getIpv6Address().getValue());
-            return actions;
-        } else {
-            // this shouldn't happen
-            LOG.error("Tunnel IP is invalid");
-            return actions;
-        }
+        RenderedServicePathHop firstRspHop = renderedServicePath.getRenderedServicePathHop().get(0);
+        RenderedServicePathHop lastRspHop = Iterables.getLast(renderedServicePath.getRenderedServicePathHop());
+        SfcNshHeader sfcNshHeader = new SfcNshHeaderBuilder().setNshTunIpDst(rspFirstHop.getIp().getIpv4Address())
+            .setNshTunUdpPort(rspFirstHop.getPort())
+            .setNshNsiToChain(firstRspHop.getServiceIndex())
+            .setNshNspToChain(renderedServicePath.getPathId())
+            .setNshNsiFromChain((short) (lastRspHop.getServiceIndex().intValue() - 1))
+            .setNshNspFromChain(renderedServicePath.getPathId())
+            .setNshMetaC1(SfcNshHeader.convertIpAddressToLong(tunnelDest.getIpv4Address()))
+            .setNshMetaC2(returnVnid)
+            .build();
+
+        // Cannot set all actions here. Some actions are destination specific, and we don't know
+        // a destination is to be
+        // chained until we reach this point. Need to write match/action in External Table for
+        // chained packets.
+        actions = addActionBuilder(actions, nxSetNsiAction(sfcNshHeader.getNshNsiToChain()), order);
+        actions = addActionBuilder(actions, nxSetNspAction(sfcNshHeader.getNshNspToChain()), order);
+        createChainTunnelFlows(sfcNshHeader, netElements, ofWriter, ctx);
+        return actions;
+    }
 
-        /*
-         * Put TunID - with NSH we don't really care about this.
-         */
-        actions = addActionBuilder(actions,
-                nxLoadTunIdAction(BigInteger.valueOf(netElements.getSrcOrds().getTunnelId()), false), order);
+    private RenderedServicePath createRsp(ServiceFunctionPath sfcPath, RspName rspName) {
+        CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder().setParentServiceFunctionPath(
+                sfcPath.getName().getValue())
+            .setName(rspName.getValue())
+            .setSymmetric(sfcPath.isSymmetric())
+            .build();
+         return SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfcPath, rspInput);
+    }
 
-        /*
-         * Set the NSH header fields, based on RSP
-         */
-         actions = addActionBuilder(actions,nxSetNsiAction(sfcNsi),order);
-         actions = addActionBuilder(actions,nxSetNspAction(sfcNsp),order);
-         /*
-         * Set up the actions to send to the destination port
-         */
-         actions = addActionBuilder(actions,outputAction(tunOpenFlowPort), order);
+    private RenderedServicePath createSymmetricRsp(RenderedServicePath rsp) {
+        if (rsp == null) {
+            return null;
+        }
+        return SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
+    }
 
-        return actions;
+    private boolean isValidRspFirstHop(RenderedServicePathFirstHop rspFirstHop) {
+        boolean valid = true;
+        if (rspFirstHop == null) {
+            LOG.error("isValidRspFirstHop: rspFirstHop is null.");
+            return false;
+        }
+        if (rspFirstHop.getIp() == null || rspFirstHop.getIp().getIpv4Address() == null
+                || rspFirstHop.getIp().getIpv6Address() != null) {
+            LOG.error("isValidRspFirstHop: rspFirstHop has invalid IP address.");
+            valid = false;
+        }
+        if (rspFirstHop.getPort() == null) {
+            LOG.error("isValidRspFirstHop: rspFirstHop has no IP port .");
+            valid = false;
+        }
+        if (rspFirstHop.getPathId() == null) {
+            LOG.error("isValidRspFirstHop: rspFirstHop has no Path Id (NSP).");
+            valid = false;
+        }
+        if (rspFirstHop.getStartingIndex() == null) {
+            LOG.error("isValidRspFirstHop: rspFirstHop has no Starting Index (NSI)");
+            valid = false;
+        }
+        return valid;
     }
 
-    private List<ActionBuilder> addActionBuilder(List<ActionBuilder> actions,
-            org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action, Integer order) {
-        ActionBuilder ab = new ActionBuilder();
-        ab.setAction(action);
-        ab.setOrder(order);
-        actions.add(ab);
-        return actions;
+    private RenderedServicePath getRspByName(RspName rspName, ReadOnlyTransaction rTx) {
+        Optional<RenderedServicePath> optRsp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
+                SfcIidFactory.rspIid(rspName), rTx);
+        if (optRsp.isPresent()) {
+            return optRsp.get();
+        }
+        return null;
     }
 
     @Override
     public boolean isValid(ActionInstance actionInstance) {
-        return validChain(actionInstance.getParameterValue());
+        return isValidGbpChain(actionInstance.getParameterValue());
     }
 
-    private boolean validChain(List<ParameterValue> paramValue) {
+    private boolean isValidGbpChain(List<ParameterValue> paramValue) {
         ParameterValue pv = getChainNameParameter(paramValue);
         if (pv == null) {
             return false;
         }
-        LOG.trace("Invoking RPC for chain {}", pv.getStringValue());
-        ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue());
-        return chain != null;
+        SfcName sfcName = new SfcName(pv.getStringValue());
+        LOG.trace("isValidGbpChain: Invoking RPC for chain {}", pv.getStringValue());
+        ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(sfcName);
+        return (chain != null);
     }
 
-    public ServiceFunctionPath getSfcPath(String chainName) {
-
+    public ServiceFunctionPath getSfcPath(SfcName chainName) {
         ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
         for (ServiceFunctionPath path : paths.getServiceFunctionPath()) {
             if (path.getServiceChainName().equals(chainName)) {
@@ -267,11 +273,27 @@ public class ChainAction extends Action {
         if (paramValueList == null)
             return null;
         for (ParameterValue pv : paramValueList) {
-            if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) {
+            if (pv.getName().getValue().equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
                 return pv;
             }
         }
         return null;
     }
 
+    private List<ActionBuilder> addActionBuilder(List<ActionBuilder> actions,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action, Integer order) {
+        ActionBuilder ab = new ActionBuilder();
+        ab.setAction(action);
+        ab.setOrder(order);
+        actions.add(ab);
+        return actions;
+    }
+
+    @Override
+    public List<SupportedParameterValues> getSupportedParameterValues() {
+        // supported parameter does not contain parameter type - it means all strings are supported
+        return ImmutableList.<SupportedParameterValues>of(new SupportedParameterValuesBuilder()
+            .setParameterName(new ParameterName(ChainActionDefinition.SFC_CHAIN_NAME)).build());
+    }
+
 }