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 fc851b0..d043f26
@@ -8,14 +8,6 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
 
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
 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;
@@ -25,8 +17,9 @@ 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.PolicyManager.FlowMap;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.PolicyPair;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcIidFactory;
@@ -36,6 +29,8 @@ 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;
@@ -47,16 +42,13 @@ import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev1407
 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.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.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.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;
@@ -69,126 +61,117 @@ 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, PolicyPair policyPair, FlowMap flowMap, OfContext ctx) {
+            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("ChainAction: 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 (chainName == null) {
+            LOG.error("updateAction: Chain name was null");
             return null;
         }
 
         /*
-         * If path is symmetrical
-         *      if src == consumer, chainName
-         *      else src == provider, chainName-Reverse.
+         * 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".
          */
-        if (sfcPath == null) {
-            LOG.error("ChainAction: SFC Path null for chain {}", chainName);
+        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.
-        String rspName = sfcPath.getName() + "-gbp-rsp";
+        RspName rspName = new RspName(sfcPath.getName() + "-gbp-rsp");
         ReadOnlyTransaction rTx = ctx.getDataBroker().newReadOnlyTransaction();
-        RenderedServicePath renderedServicePath = getRspByName(rspName, rTx);
-        if (renderedServicePath == 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 = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfcPath, rspInput);
-            if (renderedServicePath == null) {
-                LOG.error("ChainAction: Could not find or create RSP for chain {}", chainName);
+        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;
             }
+        } else {
+            renderedServicePath = rsp;
         }
 
-        RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(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;
+        }
 
+        RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName);
         if (!isValidRspFirstHop(rspFirstHop)) {
             // Errors logged in method.
             return null;
         }
 
-        NodeId tunnelDestNodeId;
-        if (netElements.getDstNodeId().equals(netElements.getLocalNodeId())) {
-            // Return destination is here
-            tunnelDestNodeId = netElements.getLocalNodeId();
-        } else {
-            tunnelDestNodeId = netElements.getDstNodeId();
-        }
+        NodeId tunnelDestNodeId=netElements.getDstNodeId();
 
-        IpAddress tunnelDest = ctx.getSwitchManager().getTunnelIP(tunnelDestNodeId, TunnelTypeVxlanGpe.class);
+        Long returnVnid = (long) netElements.getSrcEpOrds().getTunnelId();
 
+        IpAddress tunnelDest = ctx.getSwitchManager().getTunnelIP(tunnelDestNodeId, TunnelTypeVxlanGpe.class);
         if (tunnelDest == null || tunnelDest.getIpv4Address() == null) {
-            LOG.error("ChainAction: Invalid tunnelDest for NodeId: {}", tunnelDestNodeId);
+            LOG.error("updateAction: Invalid tunnelDest for NodeId: {}", tunnelDestNodeId);
             return null;
         }
 
-
         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())
@@ -196,17 +179,33 @@ public class ChainAction extends Action {
             .setNshNsiFromChain((short) (lastRspHop.getServiceIndex().intValue() - 1))
             .setNshNspFromChain(renderedServicePath.getPathId())
             .setNshMetaC1(SfcNshHeader.convertIpAddressToLong(tunnelDest.getIpv4Address()))
-            .setNshMetaC2((long) netElements.getSrcEpOrds().getTunnelId())
+            .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.
+        // 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;
+    }
 
-        createChainTunnelFlows(sfcNshHeader, netElements, flowMap, ctx);
+    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);
+    }
 
-        return actions;
+    private RenderedServicePath createSymmetricRsp(RenderedServicePath rsp) {
+        if (rsp == null) {
+            return null;
+        }
+        return SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
     }
 
     private boolean isValidRspFirstHop(RenderedServicePathFirstHop rspFirstHop) {
@@ -235,7 +234,7 @@ public class ChainAction extends Action {
         return valid;
     }
 
-    private RenderedServicePath getRspByName(String rspName, ReadOnlyTransaction rTx) {
+    private RenderedServicePath getRspByName(RspName rspName, ReadOnlyTransaction rTx) {
         Optional<RenderedServicePath> optRsp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
                 SfcIidFactory.rspIid(rspName), rTx);
         if (optRsp.isPresent()) {
@@ -254,13 +253,13 @@ public class ChainAction extends Action {
         if (pv == null) {
             return false;
         }
-        LOG.trace("Invoking RPC for chain {}", pv.getStringValue());
-        ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue());
+        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)) {
@@ -274,7 +273,7 @@ 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;
             }
         }
@@ -290,4 +289,11 @@ public class ChainAction extends Action {
         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());
+    }
+
 }