Bug 5617: policy enforcer refactor 82/35582/17
authorMatej Perina <matej.perina@pantheon.sk>
Fri, 1 Apr 2016 08:40:24 +0000 (10:40 +0200)
committerMatej Perina <matej.perina@pantheon.sk>
Fri, 1 Apr 2016 08:40:24 +0000 (10:40 +0200)
Change-Id: Ic2df05411fce29f3538464f06650f835cc284874
Signed-off-by: Matej Perina <matej.perina@pantheon.sk>
15 files changed:
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/TenantUtils.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/RuleGroupTest.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/endpoint/EndpointManager.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlows.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/mapper/policyenforcer/NetworkElements.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/mapper/policyenforcer/PolicyEnforcer.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Action.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/AllowAction.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlowsTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTableTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/mapper/MapperUtilsTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/mapper/policyenforcer/PolicyEnforcerTest.java [moved from renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcerTest.java with 66% similarity]
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainActionTest.java

index 34aaa9fcfad30bc7e1c8eb0f0320d7d107100c1f..236bddeb1a93f830c15bbd24d9242d5b29b73e74 100644 (file)
@@ -57,8 +57,10 @@ public class TenantUtils {
         @Override
         public int compare(Rule o1, Rule o2) {
             return ComparisonChain.start()
-                .compare(o1.getOrder(), o2.getOrder(), 
+                .compare(o1.getOrder(), o2.getOrder(),
                          Ordering.natural().nullsLast())
+                .compare(o1.getName().getValue(), o2.getName().getValue(),
+                        Ordering.natural().nullsLast())
                 .result();
         }
         
index 216bccae0d51d7ded87501d18c6d8ff5ab3a0a81..981660050bb5180765a5d484c17b2a631cf031c1 100644 (file)
@@ -10,9 +10,11 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.groupbasedpolicy.dto.RuleGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.Contract;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ContractKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
 
 public class RuleGroupTest {
@@ -38,6 +40,8 @@ public class RuleGroupTest {
 
         subjectValue = "value";
         when(subject.getValue()).thenReturn(subjectValue);
+        ContractId contractId = new ContractId("contract");
+        when(contract.getKey()).thenReturn(new ContractKey(contractId));
 
         ruleGroup = new RuleGroup(rules, order, contractTenant, contract, subject);
     }
index d29ccc6e0e52d277992e5878b65cedcd0ce95ff3..81bc50c2be10d86733b6aff4ba62889944896279 100755 (executable)
@@ -50,7 +50,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3Context;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
index c5ab9ca3170cfc740d6e58798b42ab3fb42545c5..d630535b35af58a368695cc578bbde30978f67c1 100755 (executable)
@@ -25,6 +25,8 @@ import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtil
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
 
 import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
@@ -32,21 +34,27 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.NetworkElements;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
@@ -142,37 +150,39 @@ public class ChainActionFlows {
     }
 
     public static void createChainTunnelFlows(SfcNshHeader sfcNshHeader, NetworkElements netElements, OfWriter ofWriter,
-            OfContext ctx) {
+            OfContext ctx, Direction direction) {
 
         NodeId localNodeId = netElements.getLocalNodeId();
-        NodeId destNodeId = netElements.getDstEp().getAugmentation(OfOverlayContext.class).getNodeId();
         EndpointFwdCtxOrdinals epOrdinals = netElements.getSrcEpOrdinals();
 
         NodeConnectorId localNodeTunPort = ctx.getSwitchManager().getTunnelPort(localNodeId, TunnelTypeVxlanGpe.class);
-        NodeConnectorId destNodeTunPort = ctx.getSwitchManager().getTunnelPort(destNodeId, TunnelTypeVxlanGpe.class);
         Ipv4Address tunDestAddress = ctx.getSwitchManager()
             .getTunnelIP(netElements.getDstNodeId(), TunnelTypeVxlanGpe.class)
             .getIpv4Address();
-        if (localNodeTunPort == null || destNodeTunPort == null) {
-            LOG.error("createChainTunnelFlows: No valid VXLAN GPE tunnel for Node {} or Node {}", localNodeId,
-                    destNodeId);
+        if (localNodeTunPort == null) {
+            LOG.error("createChainTunnelFlows: No valid VXLAN GPE tunnel for Node {} ", localNodeId);
             return;
         }
-        ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), allowFromChainPort(
-                sfcNshHeader, localNodeTunPort, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), ctx));
-
-        ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(),
-                allowFromChainTunnel(localNodeTunPort, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()));
+        if (direction.equals(Direction.In)) {
+            ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), allowFromChainPort(
+                    sfcNshHeader, localNodeTunPort, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), ctx));
 
-        ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER(),
-                createExternalFlow(sfcNshHeader, localNodeTunPort, netElements,
-                        ctx.getPolicyManager(), ctx.getSwitchManager(), tunDestAddress));
+            for (Flow flow : createChainTunnelFlow(sfcNshHeader, localNodeTunPort, netElements,
+                    ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx)) {
+                ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), flow);
+            }
 
-        ofWriter.writeFlow(destNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), createChainTunnelFlow(
-                sfcNshHeader, destNodeTunPort, epOrdinals, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
+            ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(),
+                    allowFromChainTunnel(localNodeTunPort, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()));
 
-        ofWriter.writeFlow(destNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), createChainBroadcastFlow(
-                sfcNshHeader, destNodeTunPort, epOrdinals, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
+            ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(),
+                    createChainBroadcastFlow(sfcNshHeader, localNodeTunPort, epOrdinals,
+                            ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
+        } else {
+            ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER(),
+                    createExternalFlow(sfcNshHeader, localNodeTunPort, netElements, ctx.getPolicyManager(),
+                            ctx.getSwitchManager(), tunDestAddress));
+        }
     }
 
     private static Flow createChainBroadcastFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
@@ -209,7 +219,8 @@ public class ChainActionFlows {
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action outputAction;
 
         Integer priority = 1000;
-        int matchTunnelId = sfcNshHeader.getNshMetaC2().intValue();
+        int matchTunnelId = netElements.getSrcEpOrdinals().getTunnelId();
+        long setTunnelId = netElements.getDstEpOrdinals().getTunnelId();
         Long l3c = (long) netElements.getSrcEpOrdinals().getL3Id();
         loadC1 = nxLoadNshc1RegAction(sfcNshHeader.getNshMetaC1());
 
@@ -224,9 +235,9 @@ public class ChainActionFlows {
         }
 
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadC2 =
-                nxLoadNshc2RegAction(sfcNshHeader.getNshMetaC2());
+                nxLoadNshc2RegAction(setTunnelId);
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
-                nxLoadTunIdAction(BigInteger.valueOf(sfcNshHeader.getNshMetaC2()), false);
+                nxLoadTunIdAction(BigInteger.valueOf(setTunnelId), false);
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
                 nxLoadTunIPv4Action(sfcNshHeader.getNshTunIpDst().getValue(), false);
 
@@ -248,19 +259,14 @@ public class ChainActionFlows {
         return flowb.build();
     }
 
-    private static Flow createChainTunnelFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
-            EndpointFwdCtxOrdinals epFwdCtxOrds, short tableId, OfContext ctx) {
-
-        int egId = epFwdCtxOrds.getEpgId();
-        int bdId = epFwdCtxOrds.getBdId();
-        int fdId = epFwdCtxOrds.getFdId();
-        int l3Id = epFwdCtxOrds.getL3Id();
-        int tunnelId = epFwdCtxOrds.getTunnelId();
+    private static List<Flow> createChainTunnelFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
+            NetworkElements netElements, short tableId, OfContext ctx) {
 
-        MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
-        addNxTunIdMatch(mb, tunnelId);
-        addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
-        addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
+        int egId = netElements.getDstEpOrdinals().getEpgId();
+        int bdId = netElements.getDstEpOrdinals().getBdId();
+        int fdId = netElements.getDstEpOrdinals().getFdId();
+        int l3Id = netElements.getDstEpOrdinals().getL3Id();
+        int tunnelId = netElements.getSrcEpOrdinals().getTunnelId();
 
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action segReg =
                 nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
@@ -273,13 +279,40 @@ public class ChainActionFlows {
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action vrfReg =
                 nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
 
-        Match match = mb.build();
-        FlowId flowId = FlowIdUtils.newFlowId(tableId, "chaintunnel", match);
-        FlowBuilder flowb =
-                base(tableId).setId(flowId).setPriority(150).setMatch(match).setInstructions(
-                        instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg),
-                                gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
-        return flowb.build();
+        List<Flow> flows = new ArrayList<>();
+        for (L3Address address : netElements.getDstEp().getL3Address()) {
+            Layer3Match l3Match = null;
+            MatchBuilder mb = null;
+            if (address.getIpAddress() != null) {
+                if (address.getIpAddress().getIpv4Address() != null) {
+                    l3Match = new Ipv4MatchBuilder()
+                        .setIpv4Source(new Ipv4Prefix(address.getIpAddress().getIpv4Address().getValue() + "/32"))
+                        .build();
+                    mb = new MatchBuilder().setInPort(tunPort)
+                        .setLayer3Match(l3Match)
+                        .setEthernetMatch(FlowUtils.ethernetMatch(null, null, FlowUtils.IPv4));
+                } else if (address.getIpAddress().getIpv6Address() != null) {
+                    l3Match = new Ipv6MatchBuilder()
+                        .setIpv6Source(new Ipv6Prefix(address.getIpAddress().getIpv6Address().getValue() + "/128"))
+                        .build();
+                    mb = new MatchBuilder().setInPort(tunPort)
+                        .setLayer3Match(l3Match)
+                        .setEthernetMatch(FlowUtils.ethernetMatch(null, null, FlowUtils.IPv6));
+                }
+            }
+
+            addNxTunIdMatch(mb, tunnelId);
+            addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
+            addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
+
+            Match match = mb.build();
+            FlowId flowId = FlowIdUtils.newFlowId(tableId, "chaintunnel", match);
+            FlowBuilder flowb = base(tableId).setId(flowId).setPriority(150).setMatch(match).setInstructions(
+                    instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg),
+                            gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
+            flows.add(flowb.build());
+        }
+        return flows;
     }
 
     private static Flow allowFromChainPort(SfcNshHeader sfcNshHeader, NodeConnectorId port, short tableId,
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/mapper/policyenforcer/NetworkElements.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/mapper/policyenforcer/NetworkElements.java
new file mode 100644 (file)
index 0000000..4cc50bb
--- /dev/null
@@ -0,0 +1,99 @@
+/*\r
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer;\r
+\r
+import org.opendaylight.groupbasedpolicy.dto.EgKey;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class NetworkElements {\r
+\r
+    private static final Logger LOG = LoggerFactory.getLogger(NetworkElements.class);\r
+    private final Endpoint srcEp;\r
+    private final Endpoint dstEp;\r
+    private final EgKey srcEpg;\r
+    private final EgKey dstEpg;\r
+    private NodeId srcNodeId;\r
+    private NodeId dstNodeId;\r
+    private final NodeId localNodeId;\r
+    private EndpointFwdCtxOrdinals srcEpOrdinals;\r
+    private EndpointFwdCtxOrdinals dstEpOrdinals;\r
+\r
+    public NetworkElements(Endpoint srcEp, Endpoint dstEp, EgKey srcEpg, EgKey dstEpg, NodeId nodeId, OfContext ctx) throws Exception {\r
+        this.srcEp = srcEp;\r
+        this.dstEp = dstEp;\r
+        this.srcEpg = srcEpg;\r
+        this.dstEpg = dstEpg;\r
+        this.localNodeId = nodeId;\r
+        this.srcEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);\r
+        if (this.srcEpOrdinals == null) {\r
+            LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);\r
+            return;\r
+        }\r
+        this.dstEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);\r
+        if (this.dstEpOrdinals == null) {\r
+            LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);\r
+            return;\r
+        }\r
+        if (dstEp.getAugmentation(OfOverlayContext.class) != null) {\r
+            this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();\r
+        }\r
+        if (srcEp.getAugmentation(OfOverlayContext.class) != null) {\r
+            this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();\r
+        }\r
+    }\r
+\r
+\r
+    public Endpoint getSrcEp() {\r
+        return srcEp;\r
+    }\r
+\r
+\r
+    public Endpoint getDstEp() {\r
+        return dstEp;\r
+    }\r
+\r
+    public EgKey getSrcEpg() {\r
+        return srcEpg;\r
+    }\r
+\r
+    public EgKey getDstEpg() {\r
+        return dstEpg;\r
+    }\r
+\r
+    public NodeId getSrcNodeId() {\r
+        return srcNodeId;\r
+    }\r
+\r
+\r
+    public NodeId getDstNodeId() {\r
+        return dstNodeId;\r
+    }\r
+\r
+\r
+    public NodeId getLocalNodeId() {\r
+        return localNodeId;\r
+    }\r
+\r
+\r
+    public EndpointFwdCtxOrdinals getSrcEpOrdinals() {\r
+        return srcEpOrdinals;\r
+    }\r
+\r
+\r
+    public EndpointFwdCtxOrdinals getDstEpOrdinals() {\r
+        return dstEpOrdinals;\r
+    }\r
+\r
+}
\ No newline at end of file
index 1bf9461150b060cad1fbcd8e33ee2f048ee652c5..e8f3c5379e2c3331c3c7e97ef84d1c2238b0dc15 100755 (executable)
@@ -15,6 +15,7 @@ import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtil
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -23,12 +24,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import javax.annotation.concurrent.Immutable;
-
 import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
-import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
-import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
-import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
 import org.opendaylight.groupbasedpolicy.dto.EgKey;
 import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint;
 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
@@ -44,13 +41,14 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMa
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
 import org.opendaylight.groupbasedpolicy.util.TenantUtils;
+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.sfp.rev140701.service.function.paths.ServiceFunctionPath;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -65,7 +63,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
@@ -91,91 +88,73 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ArrayListMultimap;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ComparisonChain;
-import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Ordering;
 import com.google.common.collect.Table.Cell;
 
 /**
  * <h1>Manage the table that enforces policy on the traffic. Traffic is denied
  * unless specifically allowed by policy (table=4)</h1>
- *
- * In policy enforcer, according to current {@link Policy} specific traffic is sent to SFC (nsp and nsi is set), or from SFC
+ * In policy enforcer, according to current {@link Policy} specific traffic is sent to SFC (nsp and
+ * nsi is set), or from SFC
  * to some {@link Endpoint} or to another classifier.
  * <p>
  * <i>Tunnel/overlay flows</i><br>
  * Priority = 65000 (if more flows, decrements)<br>
  * Matches:<br>
- *      - ethertype (tcp, tcp6, ipv6, icmp or missing)<br>
- *      - Reg0 {@link NxmNxReg0}<br>
- *      - Reg1 {@link NxmNxReg1}<br>
- *      - Reg2 {@link NxmNxReg2}<br>
- *      - Reg3 {@link NxmNxReg3}<br>
- *      - L3 for src_ip_prefix (if exists)<br>
- *      - L3 for dst_ip_prefix (if exists)<br>
+ * - ethertype (tcp, tcp6, ipv6, icmp or missing)<br>
+ * - Reg0 {@link NxmNxReg0}<br>
+ * - Reg1 {@link NxmNxReg1}<br>
+ * - Reg2 {@link NxmNxReg2}<br>
+ * - Reg3 {@link NxmNxReg3}<br>
+ * - L3 for src_ip_prefix (if exists)<br>
+ * - L3 for dst_ip_prefix (if exists)<br>
  * Actions:<br>
- *      - set nsi (only chain action)<br>
- *      - set nsp (only chain action)<br>
- *      - {@link GoToTable} EXTERNAL MAPPER table<br>
- *<p>
+ * - set nsi (only chain action)<br>
+ * - set nsp (only chain action)<br>
+ * - {@link GoToTable} EXTERNAL MAPPER table<br>
+ * <p>
  * <i>Allow from tunnel flow</i><br>
  * Priority = 65000<br>
  * Matches:<br>
- *      - Reg1 (set to 0xffffff) {@link NxmNxReg1}<br>
- *      - in_port (should be tunnel port) {@link NodeConnectorId}<br>
+ * - Reg1 (set to 0xffffff) {@link NxmNxReg1}<br>
+ * - in_port (should be tunnel port) {@link NodeConnectorId}<br>
  * Actions:<br>
- *      - output:port (Reg7) {@link NxmNxReg7}<br>
+ * - output:port (Reg7) {@link NxmNxReg7}<br>
  * <p>
  * Traffic is sent from one {@link EndpointGroup} to the same EPG
  * <p>
  * <i>Allow from same EPG flow</i><br>
  * Priority = 65000<br>
  * Matches:<br>
- *      - Reg0 {@link NxmNxReg0}<br>
- *      - Reg2 {@link NxmNxReg2}<br>
+ * - Reg0 {@link NxmNxReg0}<br>
+ * - Reg2 {@link NxmNxReg2}<br>
  * Actions:<br>
- *      - output:port (Reg7) {@link NxmNxReg7}
+ * - output:port (Reg7) {@link NxmNxReg7}
  * <p>
  * <i>Arp flow</i><br>
  * Priority = 20000<br>
  * Matches:<br>
- *      - ethernet match (arp)<br>
- *      - Reg5 {@link NxmNxReg5}<br>
+ * - ethernet match (arp)<br>
+ * - Reg5 {@link NxmNxReg5}<br>
  * Actions:<br>
- *      - output:port (Reg7) {@link NxmNxReg7}
- *
+ * - output:port (Reg7) {@link NxmNxReg7}
  */
 public class PolicyEnforcer extends FlowTable {
 
     private static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
     public static short TABLE_ID;
-    private static boolean isReversedPolicy;
     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoEgressNatInstruction;
     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoExternalInstruction;
-    private HashSet<PolicyPair> visitedPairs = new HashSet<>();
-    private HashSet<PolicyPair> visitedReversePairs = new HashSet<>();
-    private List<Rule> reversedActiveRules = new ArrayList<>();
-    private ListMultimap<EgKey, EgKey> resolvedEpgPairs = ArrayListMultimap.create();
-    private boolean directPathFlowsCreated = false;
-    private boolean reversePathFlowsCreated = false;
 
     public PolicyEnforcer(OfContext ctx, short tableId) {
         super(ctx);
         TABLE_ID = tableId;
-        isReversedPolicy = false;
         gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
         gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER());
     }
 
-    private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
-        return gotoEgressNatInstruction;
-    }
-
-    private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
-        return gotoExternalInstruction;
-    }
-
     @Override
     public short getTableId() {
         return TABLE_ID;
@@ -183,8 +162,9 @@ public class PolicyEnforcer extends FlowTable {
 
     @Override
     public void sync(Endpoint endpoint, OfWriter ofWriter) throws Exception {
+        Preconditions.checkNotNull(endpoint);
+        Preconditions.checkNotNull(ofWriter);
 
-        // TODO: only temporary workaround, use src & dst endpoint in implementation
         NodeId nodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint);
 
         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
@@ -193,486 +173,250 @@ public class PolicyEnforcer extends FlowTable {
         if (tunPort != null) {
             ofWriter.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
         }
+        EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
+                OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint);
+        if (srcEpFwdCxtOrdinals == null) {
+            LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", endpoint);
+            return;
+        }
+        for (EgKey sourceEpg : ctx.getEndpointManager().getEgKeysForEndpoint(endpoint)) {
+            for (EgKey destEpg : ctx.getCurrentPolicy().getPeers(sourceEpg)) {
+                Collection<Endpoint> destinationEndpoints = getEndpointsForGroup(destEpg);
+                for (Endpoint destinationEndpoint : destinationEndpoints) {
+                    EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
+                            OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEndpoint);
+                    if (dstEpFwdCxtOrdinals == null) {
+                        LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEndpoint);
+                        continue;
+                    }
 
-        visitedPairs = new HashSet<>();
-        reversedActiveRules = new ArrayList<>();
-        visitedReversePairs = new HashSet<>();
-        resolvedEpgPairs = ArrayListMultimap.create();
-
-        // Used for ARP flows
-        Set<Integer> fdIds = new HashSet<>();
-
-        for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
-            for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
-                Set<EgKey> peers = ctx.getCurrentPolicy().getPeers(sourceEpgKey);
-                for (EgKey destinationEpgKey : peers) {
-
-                    Set<Endpoint> destinationEndpoints = new HashSet<>();
-                    destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(destinationEpgKey));
-                    destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(destinationEpgKey));
-                    for (Endpoint destinationEp : destinationEndpoints) {
-
-                        EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
-                        if (srcEpFwdCxtOrdinals == null) {
-                            LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", sourceEp);
-                            continue;
-                        }
-
-                        EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEp);
-                        if (dstEpFwdCxtOrdinals == null) {
-                            LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEp);
-                            continue;
-                        }
-
-                        fdIds.add(srcEpFwdCxtOrdinals.getFdId());
-                        NetworkElements netElements = new NetworkElements(sourceEp, destinationEp, sourceEpgKey,
-                                destinationEpgKey, nodeId, ctx);
+                    NetworkElements netElements =
+                            new NetworkElements(endpoint, destinationEndpoint, sourceEpg, destEpg, nodeId, ctx);
 
-                        // Get policy in both directions
-                        Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destinationEpgKey, sourceEpgKey);
-                        Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpgKey, destinationEpgKey);
-                        reversedActiveRules = getRules(getActiveRulesBetweenEps(destinationEpgPolicy, sourceEp, destinationEp));
+                    // Get policy in both directions
+                    Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destEpg, sourceEpg);
+                    Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpg, destEpg);
 
-                        // Resolve flows in both directions if possible according to policy. Get back status of resolution
-                        PathStatus status = resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy);
+                    // Resolve flows in both directions if possible according to policy. Get back
+                    // status
+                    // of resolution
+                    resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy, destinationEpgPolicy);
 
-                        // When source Epg policy creates no flows, destination Epg policy has to be resolved
-                        if (status.equals(PathStatus.none)) {
-                            resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, false);
-                        }
-                        // When source Epg policy creates flows only in one direction, the other direction has to be
-                        // created here. Is essential to revert directions to prevent flow overriding and incorrect nsp
-                        // evaluation
-                        else if (status.equals(PathStatus.partial)) {
-                            resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, true);
-                        }
-                    }
+                    ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(srcEpFwdCxtOrdinals.getFdId()));
                 }
             }
-        }
-
-        // Allow same EPG
-        allowSameEpg(nodeId, ofWriter);
-
-        // Write ARP flows per flood domain
-        for (Integer fdId : fdIds) {
-            ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
+            // Allow same EPG
+            allowSameEpg(sourceEpg, endpoint, nodeId, ofWriter);
         }
     }
 
-    private PathStatus resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy) {
-        isReversedPolicy = false;
-        directPathFlowsCreated = false;
-        reversePathFlowsCreated = false;
+    private Set<Endpoint> getEndpointsForGroup(EgKey epg) {
+        Set<Endpoint> destinationEndpoints = new HashSet<>();
+        destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(epg));
+        destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(epg));
+        return destinationEndpoints;
+    }
 
-        for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
-                directPolicy, netElements.getDstEp(), netElements.getSrcEp())) {
-            Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
-                    .getL3EpPrefixes());
-            Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
-                    .getL3EpPrefixes());
+    private void resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy,
+            Policy reversedPolicy) {
 
-            int priority = 65000;
-            for (RuleGroup rg : activeRulesByConstraints.getValue()) {
+        List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> providedRules =
+                getActiveRulesBetweenEps(directPolicy, netElements.getDstEp(), netElements.getSrcEp());
+        List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> consumedRules =
+                getActiveRulesBetweenEps(reversedPolicy, netElements.getSrcEp(), netElements.getDstEp());
+        List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules;
+        if (!providedRules.isEmpty()) {
+            activeRules = providedRules;
+        } else {
+            activeRules = consumedRules;
+        }
+        int priority = 65000;
+        for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : activeRules) {
+            Set<IpPrefix> sIpPrefixes;
+            Set<IpPrefix> dIpPrefixes;
+            if (providedRules.contains(activeRulesByConstraints)) {
+                sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey().getL3EpPrefixes());
+                dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey().getL3EpPrefixes());
+            } else {
+                sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey().getL3EpPrefixes());
+                dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey().getL3EpPrefixes());
+            }
+            for (RuleGroup rg : Ordering.from(new RuleGroupComparator())
+                .immutableSortedCopy(activeRulesByConstraints.getValue())) {
                 TenantId tenantId = rg.getContractTenant().getId();
                 IndexedTenant tenant = ctx.getTenant(tenantId);
-                for (Rule rule : rg.getRules()) {
-
-                    // Find all rules in the same traffic direction
-                    List<Rule> sameDirectionRules = findRulesInSameDirection(rule, reversedActiveRules);
-                    if (sameDirectionRules.isEmpty()) {
-                        sameDirectionRules.add(rule);
+                for (Direction direction : new Direction[] {Direction.In, Direction.Out}) {
+                    List<Rule> sameDirectionRules;
+                    if (providedRules.contains(activeRulesByConstraints)) {
+                        sameDirectionRules = uniteRulesByDirection(direction, rg.getRules(), getRules(consumedRules));
+                    } else {
+                        sameDirectionRules = uniteRulesByDirection(direction, null, rg.getRules());
                     }
-                    sameDirectionRules = Ordering.from(TenantUtils.RULE_COMPARATOR)
-                            .immutableSortedCopy(sameDirectionRules);
-
-                    // Create flows for every pair of rules
-                    for (Rule oppositeRule : sameDirectionRules) {
-
-                        // Evaluate which rule has more specific matches
-                        Rule ruleWithMatches = findRuleWithSpecificMatches(rule, oppositeRule, tenant);
-                        Rule ruleWithActions = mergeRuleActions(rule, oppositeRule, tenant);
-                        if (ruleWithMatches == null) {
-                            LOG.trace("No matches found for pair of rules {}, {}", rule, oppositeRule);
-                            continue;
-                        }
-                        if (ruleWithActions == null) {
-                            LOG.trace("No actions found for pair of rules {}, {}", rule, oppositeRule);
-                            continue;
-                        }
-                        PolicyPair policyPair = null;
-                        if (rule.equals(ruleWithMatches)) {
-                            policyPair = new PolicyPair(netElements.getDstEpOrdinals().getEpgId(),
-                                    netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getCgId(),
-                                    netElements.getSrcEpOrdinals().getCgId(), dIpPrefixes, sIpPrefixes,
-                                    netElements.getDstNodeId(), netElements.getSrcNodeId());
-                        } else {
-                            policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(),
-                                    netElements.getDstEpOrdinals().getEpgId(), netElements.getSrcEpOrdinals().getCgId(),
-                                    netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
-                                    netElements.getSrcNodeId(), netElements.getDstNodeId());
-                        }
-                        LOG.trace("PolicyEnforcer: Visiting PolicyPair {} endpoints {} {}", policyPair,
-                                netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
-
-                        // Preserve original rule direction
-                        Set<Direction> directions = getRuleDirections(rule);
-
-                        for(Direction direction : directions) {
-
-                            // Create list of matches/actions. Also creates chain flows when specific action requires it
-                            List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant,
-                                    ruleWithMatches);
-                            List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant,
-                                    ruleWithMatches);
-
-                            List<ActionBuilder> actions = createActions(ofWriter, netElements, direction,
-                                    policyPair, tenant, ruleWithActions, false);
-
-                            // Compose flows
-                            createFlows(inMatches, actions, netElements, ofWriter, priority);
-                            createFlows(outMatches, actions, netElements, ofWriter, priority);
-
-                            priority -= 1;
-
-                            // Keep info about what direction has flows already created
-                            if (direction.equals(Direction.In)) {
-                                directPathFlowsCreated = true;
-                            }
-                            if (direction.equals(Direction.Out)) {
-                                reversePathFlowsCreated = true;
-                            }
-
-                            // Fully resolved Ep groups are saved to prevent duplicates
-                            if (directPathFlowsCreated && reversePathFlowsCreated) {
-                                LOG.trace("Epg pair added: {}, {} ", netElements.getSrcEpg(), netElements.getDstEpg());
-                                resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
-                            }
-                        }
+                    for (Rule rule : Ordering.from(TenantUtils.RULE_COMPARATOR)
+                        .immutableSortedCopy(sameDirectionRules)) {
+                        createFlowsForRule(rule, getRules(providedRules), getRules(consumedRules), direction,
+                                netElements, ofWriter, tenant, sIpPrefixes, dIpPrefixes, priority);
+                        priority--;
                     }
                 }
             }
-
-        }
-        // Returns appropriate result of resolving
-        if (directPathFlowsCreated && reversePathFlowsCreated) {
-            return PathStatus.both;
-        } else if ((!directPathFlowsCreated && reversePathFlowsCreated) || (directPathFlowsCreated && !reversePathFlowsCreated)) {
-            return PathStatus.partial;
-        } else {
-            return PathStatus.none;
-        }
-    }
-
-    private Set<Direction> getRuleDirections(Rule ruleWithMatches) {
-        Set<Direction> directions = new HashSet<>();
-        for (ClassifierRef classifierRef : ruleWithMatches.getClassifierRef()) {
-            if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.In) {
-                directions.add(classifierRef.getDirection());
-            }
-            if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.Out) {
-                directions.add(classifierRef.getDirection());
-            }
-        }
-        if (directions.isEmpty()) {
-            directions.add(Direction.Bidirectional);
         }
-        return directions;
     }
 
-    private Rule mergeRuleActions(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
-        if (oppositeRule.equals(rule)) {
-            return rule;
-        }
-
-        Action ruleAction = null;
-        Action oppositeRuleAction = null;
 
-        // For now, only allow action and chain action is supported
-        for (ActionRef actionRef : rule.getActionRef()) {
-            ActionInstance actionInstance = tenant.getAction(actionRef.getName());
-            if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
-                ruleAction = new AllowAction();
-            }
-            if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
-                ruleAction = new ChainAction();
-            }
-        }
-        for (ActionRef actionRef : oppositeRule.getActionRef()) {
-            ActionInstance actionInstance = tenant.getAction(actionRef.getName());
-            if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
-                oppositeRuleAction = new AllowAction();
-            }
-            if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
-                oppositeRuleAction = new ChainAction();
-            }
-        }
-
-        if (ruleAction == null && oppositeRuleAction == null) {
-            return null;
-        } else if (ruleAction != null && ruleAction.getClass().equals(AllowAction.class)) {
-            return oppositeRule;
-        } else if (oppositeRuleAction != null && oppositeRuleAction.getClass().equals(AllowAction.class)) {
-            return rule;
-        } else {
-            // TODO both rules have chain action - add support for more different chain actions. This works for now
-            return rule;
-        }
+    private List<Rule> uniteRulesByDirection (Direction direction, List<Rule> directRules, List<Rule> reversedRules) {
+        List<Rule> sameDirectionRules = findRulesInDirection(direction, directRules);
+        sameDirectionRules
+            .addAll(findRulesInDirection(reverse(direction), reversedRules));
+        return sameDirectionRules;
     }
 
-    private Rule findRuleWithSpecificMatches(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
-        if (oppositeRule.equals(rule)) {
-            return rule;
-        }
-
-        // TODO check all classifierRefs
-        ClassifierRef ruleClassifierRef = rule.getClassifierRef().get(0);
-        ClassifierRef oppositeRuleClassifierRef = oppositeRule.getClassifierRef().get(0);
-
-        ClassifierInstance ruleClassifierInstance = tenant.getClassifier(ruleClassifierRef.getInstanceName());
-        ClassifierInstance oppositeRuleClassifierInstance = tenant.getClassifier(oppositeRuleClassifierRef.getInstanceName());
-
-        if (ruleClassifierInstance == null) {
-            LOG.trace("Classifier instance not found, ClassifierRef name: {} ", ruleClassifierRef.getInstanceName());
-            return null;
-        }
-        if (oppositeRuleClassifierInstance == null) {
-            LOG.trace("Opposite classifier instance not found, ClassifierRef name: {} ", oppositeRuleClassifierRef.getInstanceName());
-            return null;
-        }
-
-        // Check ethertype. Values must be equal
-        for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
-            for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
-                if ((ruleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
-                        && oppositeRuleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)) {
-                    if (!ruleParameter.getIntValue().equals(oppositeRuleParameter.getIntValue())) {
-                        LOG.trace("Ethertype values are not equal, rule: {}, opposite rule: {} ", rule, oppositeRule);
-                        return null;
-                    }
-                }
-            }
-        }
-        // Check proto if exists. Values must be equal or missing
-        ParameterValue ruleProtoParameter = null;
-        ParameterValue oppositeRuleProtoParameter = null;
-        for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
-            if (ruleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
-                ruleProtoParameter = ruleParameter;
-            }
-        }
-        for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
-            if (oppositeRuleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
-                oppositeRuleProtoParameter = oppositeRuleParameter;
-            }
-        }
-
-        if (ruleProtoParameter == null || ruleProtoParameter.getIntValue() == null) {
-            return oppositeRule;
-        } else if (oppositeRuleProtoParameter == null || oppositeRuleProtoParameter.getIntValue() == null) {
-            return rule;
-        } else if (!ruleProtoParameter.getIntValue().equals(oppositeRuleProtoParameter.getIntValue())) {
-            LOG.trace("Proto parameters are not equal, rule parameters: {}, opposite rule parameters {} ",
-                    ruleProtoParameter, oppositeRuleProtoParameter);
-            return null;
-        }
-
-        // Check ports
-        // TODO add support for port ranges
-        ParameterValue ruleL4Src = null;
-        ParameterValue oppositeRuleL4Src = null;
-        ParameterValue ruleL4Dst = null;
-        ParameterValue oppositeRuleL4Dst = null;
-
-        for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
-            if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
-                ruleL4Src = ruleParameter;
-            }
-            if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
-                ruleL4Dst = ruleParameter;
-            }
-        }
-        for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
-            if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
-                oppositeRuleL4Src = oppositeRuleParameter;
-            }
-            if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
-                oppositeRuleL4Dst = oppositeRuleParameter;
-            }
-        }
-
-        if (ruleL4Src == null && ruleL4Dst == null && oppositeRuleL4Src == null && oppositeRuleL4Dst == null) {
-            return rule;
-        }
-
-        // Source rules
-        if (ruleL4Src == null && oppositeRuleL4Src != null) {
-            return oppositeRule;
-        }
-        if (ruleL4Src != null && oppositeRuleL4Src == null) {
-            return rule;
-        }
-        if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
-                && ruleL4Src.equals(oppositeRuleL4Src)) {
-            return rule;
-        }
-        if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
-                && !ruleL4Src.equals(oppositeRuleL4Src)) {
-            return null;
-        }
-
-        // Destination rules
-        if (ruleL4Dst == null && oppositeRuleL4Dst != null) {
-            return oppositeRule;
-        }
-        if (ruleL4Dst != null && oppositeRuleL4Dst == null) {
-            return rule;
+    private void createFlowsForRule(Rule rule, List<Rule> providedRules, List<Rule> consumedRules,
+            Direction direction, NetworkElements netElements,OfWriter ofWriter, IndexedTenant tenant, Set<IpPrefix> sIpPrefixes,
+            Set<IpPrefix> dIpPrefixes, int priority) {
+        List<Rule> reverseProvidedRules = findRulesInDirection(reverse(direction), providedRules);
+        List<String> resolvedSymmetricChains =
+                resolveSymetricChainActions(direction, rule, tenant, reverseProvidedRules, consumedRules);
+        if (resolvedSymmetricChains == null) {
+            LOG.debug("Rule {} skipped. Reason: asymmetric use of symmetric chain", rule);
+            return;
         }
-        if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
-                && ruleL4Dst.equals(oppositeRuleL4Dst)) {
-            return rule;
+        // Create list of matches/actions. Also creates chain flows when
+        // specific action requires it
+        List<MatchBuilder> matches = null;
+        if (consumedRules.contains(rule)) {
+            matches = createMatches(direction, reverse(direction), netElements, tenant, rule,
+                    sIpPrefixes, dIpPrefixes);
+        } else {
+            matches = createMatches(direction, direction, netElements, tenant, rule, sIpPrefixes,
+                    dIpPrefixes);
         }
-        if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
-                && !ruleL4Dst.equals(oppositeRuleL4Dst)) {
-            return null;
+        List<ActionBuilder> actions = createActions(ofWriter, netElements, direction, tenant, rule,
+                resolvedSymmetricChains);
+        if (actions == null) {
+            return;
         }
 
-        return null;
+        // Compose flows
+        createFlows(matches, actions, netElements, ofWriter, priority);
     }
 
-    private void resolveDestinationEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy reversedPolicy,
-                                             boolean isReverted) {
-        isReversedPolicy = true;
-        for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
-                reversedPolicy, netElements.getSrcEp(), netElements.getDstEp())) {
-            Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
-                    .getL3EpPrefixes());
-            Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
-                    .getL3EpPrefixes());
-            PolicyPair policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getEpgId(),
-                    netElements.getSrcEpOrdinals().getCgId(), netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
-                    netElements.getSrcNodeId(), netElements.getDstNodeId());
-            if (visitedReversePairs.contains(policyPair)) {
-                LOG.trace(
-                        "PolicyEnforcer: Reverse: Already visited PolicyPair {}, endpoints {} {} skipped",
-                        policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
-                continue;
-            } else {
-                LOG.trace("PolicyEnforcer: Reverse: Visiting: PolicyPair {} via endpoints {} {}",
-                        policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
-                visitedReversePairs.add(policyPair);
-
-            }
-            int priority = 65000;
-            for (RuleGroup rg : activeRulesByConstraints.getValue()) {
-                TenantId tenantId = rg.getContractTenant().getId();
-                IndexedTenant tenant = ctx.getTenant(tenantId);
-                for (Rule rule : rg.getRules()) {
+    private List<String> resolveSymetricChainActions(Direction direction, Rule rule, IndexedTenant tenant,
+            List<Rule> reversedProvidedRules, List<Rule> consumedRules) {
+        List<String> chainNames = new ArrayList<>();
+        if (rule.getActionRef() != null) {
 
-                    Set<Direction> directions = getRuleDirections(rule);
-                    if (directions.isEmpty()) {
+            for (ActionRef actionRef : rule.getActionRef()) {
+                ActionInstance actionInstance = tenant.getAction(actionRef.getName());
+                if (actionInstance == null) {
+                    continue;
+                }
+                Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
+                if (action == null) {
+                    continue;
+                }
+                if (action instanceof ChainAction) {
+                    chainNames = getSymetricChainNames(actionInstance);
+                    if (chainNames.isEmpty()) {
                         continue;
                     }
+                    List<Rule> reversedRules = findRulesInDirection(reverse(direction), reversedProvidedRules);
+                    reversedRules.addAll(findRulesInDirection(direction, consumedRules));
 
-                    for(Direction direction : directions) {
-
-                        // When specific direction flows exists, do not create them again
-                        if (direction.equals(Direction.In) && reversePathFlowsCreated) {
+                    List<String> oppositeChainNames = new ArrayList<>();
+                    for (Rule oppositeRule : reversedRules) {
+                        if (oppositeRule.getActionRef() == null) {
                             continue;
                         }
-                        if (direction.equals(Direction.Out) && directPathFlowsCreated) {
-                            continue;
-                        }
-
-                        List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant, rule);
-                        List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant, rule);
-
-                        // In case chain action is called here, it has to know that this is reversed policy to set tunnel
-                        // ordinal correctly
-                        List<ActionBuilder> inActions = createActions(ofWriter, netElements, Direction.In, policyPair, tenant,
-                                rule, isReverted);
-                        List<ActionBuilder> outActions = createActions(ofWriter, netElements, Direction.Out, policyPair, tenant,
-                                rule, isReverted);
-
-                        createFlows(inMatches, inActions, netElements, ofWriter, priority);
-                        createFlows(outMatches, outActions, netElements, ofWriter, priority);
-
-                        if (direction.equals(Direction.In)) {
-                            reversePathFlowsCreated = true;
-                        }
-                        if (direction.equals(Direction.Out)) {
-                            directPathFlowsCreated = true;
-                        }
-
-                        priority -= 1;
+                        for (ActionRef oppositeActionRef : oppositeRule.getActionRef()) {
+                            ActionInstance oppositeActionInstance = tenant.getAction(oppositeActionRef.getName());
+                            if (oppositeActionInstance == null) {
+                                continue;
+                            }
+                            Action oppositeAction = SubjectFeatures.getAction(oppositeActionInstance.getActionDefinitionId());
+                            if (oppositeAction == null) {
+                                continue;
+                            }
+                            if (oppositeAction instanceof ChainAction) {
+                                oppositeChainNames.addAll(getSymetricChainNames(oppositeActionInstance));
 
-                        if (directPathFlowsCreated && reversePathFlowsCreated) {
-                            resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
+                            }
                         }
                     }
+                    if (!oppositeChainNames.containsAll(chainNames)) {
+                        return null;
+                    }
+                    if ((consumedRules.contains(rule) && (direction.equals(Direction.In)))
+                            || ((!consumedRules.contains(rule)) && direction.equals(Direction.Out))) {
+                        return new ArrayList<>();
+                    }
                 }
             }
         }
+        return chainNames;
     }
 
-    private void allowSameEpg(NodeId nodeId, OfWriter ofWriter) throws Exception {
-        for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
-            for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
+    private List<String> getSymetricChainNames(ActionInstance action) {
+        List<String> chainNames = new ArrayList<>();
+        for (ParameterValue param : action.getParameterValue()) {
+            if (param.getStringValue() != null
+                    && param.getName().getValue().equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
+                String chainName = param.getStringValue();
+                ServiceFunctionPath sfcPath = ChainAction.getSfcPath(new SfcName(chainName));
+                if (sfcPath == null || sfcPath.getName() == null) {
+                    continue;
+                }
+                if (sfcPath.isSymmetric()) {
+                    chainNames.add(param.getStringValue());
+                }
+            }
+        }
+        return chainNames;
+    }
 
-                IndexedTenant tenant = ctx.getTenant(sourceEpgKey.getTenantId());
-                if (tenant != null) {
-                    EndpointGroup group = tenant.getEndpointGroup(sourceEpgKey.getEgId());
-                    if (group == null) {
-                        LOG.debug("EPG {} does not exit and is used in EP {}", sourceEpgKey, sourceEp.getKey());
-                        continue;
-                    }
-                    IntraGroupPolicy igp = group.getIntraGroupPolicy();
-
-                    if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
-                        for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(sourceEpgKey)) {
-                            EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
-                                    OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
-                            if (srcEpFwdCxtOrdinals == null) {
-                                LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
-                                continue;
-                            }
+    private void allowSameEpg(EgKey epgKey, Endpoint sourceEp, NodeId nodeId, OfWriter ofWriter) throws Exception {
 
-                            EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
-                                    OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
-                            if (dstEpFwdCxtOrdinals == null) {
-                                LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
-                                continue;
-                            }
+        IndexedTenant tenant = ctx.getTenant(epgKey.getTenantId());
+        if (tenant != null) {
+            EndpointGroup group = tenant.getEndpointGroup(epgKey.getEgId());
+            if (group == null) {
+                LOG.debug("EPG {} does not exit and is used ", epgKey);
+                return;
+            }
+            IntraGroupPolicy igp = group.getIntraGroupPolicy();
 
-                            int destinationEpgId = dstEpFwdCxtOrdinals.getEpgId();
-                            int sourceEpgId = srcEpFwdCxtOrdinals.getEpgId();
-                            ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(sourceEpgId, destinationEpgId));
-                            ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(destinationEpgId, sourceEpgId));
-                        }
-                    }
+            if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
+                EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
+                if (srcEpFwdCxtOrdinals == null) {
+                    LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
                 }
+                int epgId = srcEpFwdCxtOrdinals.getEpgId();
+                ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(epgId));
             }
         }
     }
 
     // Return list of all rules with opposite direction
-    private List<Rule> findRulesInSameDirection(Rule ruleToResolve, List<Rule> reversedRules) {
+    private List<Rule> findRulesInDirection(Direction direction, List<Rule> rules) {
         List<Rule> sameDirectionRules = new ArrayList<>();
-        for (Rule ruleToCompare : reversedRules) {
-            for (ClassifierRef classifierRefToCompare : ruleToCompare.getClassifierRef()) {
-                for (ClassifierRef classifierRefToResolve : ruleToResolve.getClassifierRef()) {
-                    if (isDirectionOpposite(classifierRefToCompare.getDirection(), classifierRefToResolve.getDirection())) {
-                        sameDirectionRules.add(ruleToCompare);
-                    }
+        if (rules != null) {
+            for (Rule ruleToCompare : rules) {
+                if (isSameDirection(direction, ruleToCompare)) {
+                    sameDirectionRules.add(ruleToCompare);
                 }
             }
         }
         return sameDirectionRules;
     }
 
-    private boolean isDirectionOpposite(Direction one, Direction two) {
-        return ((one.equals(Direction.In) && two.equals(Direction.Out))
-                || (one.equals(Direction.Out) && two.equals(Direction.In)));
+    private boolean isSameDirection(Direction direction, Rule rule) {
+        for (ClassifierRef classifier : rule.getClassifierRef()) {
+            if (direction.equals(classifier.getDirection()) || direction.equals(Direction.Bidirectional)
+                    || Direction.Bidirectional.equals(classifier.getDirection())) {
+                return true;
+            }
+        }
+        return false;
     }
 
     private List<Rule> getRules(List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules) {
@@ -700,23 +444,20 @@ public class PolicyEnforcer extends FlowTable {
         Match match = mb.build();
         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
         return base().setPriority(priority)
-                .setId(flowid)
-                .setMatch(match)
-                .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
-                .build();
+            .setId(flowid)
+            .setMatch(match)
+            .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
+            .build();
     }
 
-    private Flow allowSameEpg(int sourceEpgId, int destinationEpgId) {
+    private Flow allowSameEpg(int epgId) {
 
         MatchBuilder mb = new MatchBuilder();
-        addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) sourceEpgId),
-                RegMatch.of(NxmNxReg2.class, (long) destinationEpgId));
+        addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) epgId), RegMatch.of(NxmNxReg2.class, (long) epgId));
         Match match = mb.build();
         FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
-        FlowBuilder flow = base().setId(flowId)
-                .setMatch(match)
-                .setPriority(65000)
-                .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
+        FlowBuilder flow = base().setId(flowId).setMatch(match).setPriority(65000).setInstructions(
+                instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
         return flow.build();
     }
 
@@ -726,22 +467,21 @@ public class PolicyEnforcer extends FlowTable {
         addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
         Match match = mb.build();
         FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
-        FlowBuilder flow = base().setId(flowId)
-                .setMatch(match)
-                .setPriority(65000)
-                .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
+        FlowBuilder flow = base().setId(flowId).setMatch(match).setPriority(65000).setInstructions(
+                instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
         return flow.build();
 
     }
 
-    private List<MatchBuilder> createMatches(Direction direction, PolicyPair policyPair, IndexedTenant contractTenant,
-                                             Rule rule) {
+    private List<MatchBuilder> createMatches(Direction flowDirection, Direction classifierDirection,
+            NetworkElements netElements, IndexedTenant contractTenant, Rule rule, Set<IpPrefix> sIpPrefixes,
+            Set<IpPrefix> dIpPrefixes) {
         Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
         Set<ClassifierDefinitionId> classifiers = new HashSet<>();
         for (ClassifierRef cr : rule.getClassifierRef()) {
 
             if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
-                    && !cr.getDirection().equals(direction)) {
+                    && !cr.getDirection().equals(classifierDirection)) {
                 continue;
             }
 
@@ -778,24 +518,25 @@ public class PolicyEnforcer extends FlowTable {
         if (classifiers.isEmpty()) {
             return null;
         }
-        List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
+        List<Map<String, ParameterValue>> derivedParamsByName =
+                ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
         List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
         for (Map<String, ParameterValue> params : derivedParamsByName) {
             List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
-            if (policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
-                matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, null));
-            } else if (!policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
-                for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
-                    matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, null));
+            if (sIpPrefixes.isEmpty() && dIpPrefixes.isEmpty()) {
+                matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, null, null));
+            } else if (!sIpPrefixes.isEmpty() && dIpPrefixes.isEmpty()) {
+                for (IpPrefix sIpPrefix : sIpPrefixes) {
+                    matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, sIpPrefix, null));
                 }
-            } else if (policyPair.consumerEicIpPrefixes.isEmpty() && !policyPair.providerEicIpPrefixes.isEmpty()) {
-                for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
-                    matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, dIpPrefix));
+            } else if (sIpPrefixes.isEmpty() && !dIpPrefixes.isEmpty()) {
+                for (IpPrefix dIpPrefix : dIpPrefixes) {
+                    matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, null, dIpPrefix));
                 }
             } else {
-                for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
-                    for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
-                        matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, dIpPrefix));
+                for (IpPrefix sIpPrefix : sIpPrefixes) {
+                    for (IpPrefix dIpPrefix : dIpPrefixes) {
+                        matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, sIpPrefix, dIpPrefix));
                     }
                 }
             }
@@ -814,8 +555,8 @@ public class PolicyEnforcer extends FlowTable {
         return flowMatchBuilders;
     }
 
-    private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction, PolicyPair policyPair,
-                                              IndexedTenant contractTenant, Rule rule, boolean isReversedDirection) {
+    private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction,
+            IndexedTenant contractTenant, Rule rule, List<String> resolvedSymmetricChains) {
         List<ActionBuilder> actionBuilderList = new ArrayList<>();
         if (rule.getActionRef() != null) {
 
@@ -823,11 +564,11 @@ public class PolicyEnforcer extends FlowTable {
             List<ActionRef> actionRefList = new ArrayList<>(rule.getActionRef());
             Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
 
-            for (ActionRef actionRule : actionRefList) {
-                ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
+            for (ActionRef actionRef : actionRefList) {
+                ActionInstance actionInstance = contractTenant.getAction(actionRef.getName());
                 if (actionInstance == null) {
                     // XXX TODO fail the match and raise an exception
-                    LOG.warn("Action instance {} not found", actionRule.getName().getValue());
+                    LOG.warn("Action instance {} not found", actionRef.getName().getValue());
                     return null;
                 }
                 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
@@ -849,15 +590,16 @@ public class PolicyEnforcer extends FlowTable {
                         }
                     }
                 }
-                if (isReversedDirection) {
-                    direction = reverse(direction);
+                if (action instanceof ChainAction) {
+                    ((ChainAction) action).setResolvedSymmetricChains(resolvedSymmetricChains);
                 }
 
                 // Convert the GBP Action to one or more OpenFlow Actions
-                if (!(actionRefList.indexOf(actionRule) == (actionRefList.size() - 1)
-                        && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId())))) {
-                    actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(), netElements,
-                            policyPair, ofWriter, ctx, direction);
+                if ((!(actionRefList.indexOf(actionRef) == (actionRefList.size() - 1)
+                        && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId()))))
+                        && actionBuilderList != null) {
+                    actionBuilderList = action.updateAction(actionBuilderList, params, actionRef.getOrder(),
+                            netElements, ofWriter, ctx, direction);
                 }
             }
         }
@@ -865,22 +607,20 @@ public class PolicyEnforcer extends FlowTable {
         return actionBuilderList;
     }
 
-    private Direction reverse(Direction direction) {
+    public static Direction reverse(Direction direction) {
         if (direction.equals(Direction.In)) {
             return Direction.Out;
-        }
-        else if(direction.equals(Direction.Out)) {
+        } else if (direction.equals(Direction.Out)) {
             return Direction.In;
-        }
-        else {
+        } else {
             return Direction.Bidirectional;
         }
     }
 
-    private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList, NetworkElements netElements,
-                             OfWriter ofWriter, int priority) {
+    private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList,
+            NetworkElements netElements, OfWriter ofWriter, int priority) {
         FlowBuilder flow = base().setPriority(priority);
-        if(flowMatchBuilders == null) {
+        if (flowMatchBuilders == null) {
             return;
         }
         for (MatchBuilder mb : flowMatchBuilders) {
@@ -899,22 +639,23 @@ public class PolicyEnforcer extends FlowTable {
                 .getExternalImplicitGroup();
             boolean performNat = false;
             for (EndpointL3 natEp : ctx.getEndpointManager().getL3EndpointsWithNat()) {
-                if (natEp.getMacAddress() != null &&
-                    natEp.getL2Context() != null &&
-                    netElements.getSrcEp().getKey().equals(new EndpointKey(natEp.getL2Context(),
-                        natEp.getMacAddress())) &&
-                    EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
+                if (natEp.getMacAddress() != null && natEp.getL2Context() != null
+                        && netElements.getSrcEp()
+                            .getKey()
+                            .equals(new EndpointKey(natEp.getL2Context(), natEp.getMacAddress()))
+                        && EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
                     performNat = true;
                     break;
                 }
             }
             if (actionBuilderList == null) {
-                //TODO - analyse, what happen for unknown action, SFC, etc.
-                LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
+                // flow with this match should not appear on switch (e.g. chain action IN)
+                // //TODO - analyse, what happen for unknown action, SFC, etc.
                 continue;
             }
             if (actionBuilderList.isEmpty()) {
-                flow.setInstructions((performNat == true) ? instructions(gotoEgressNatInstruction) : instructions(gotoExternalInstruction));
+                flow.setInstructions((performNat == true) ? instructions(gotoEgressNatInstruction) : instructions(
+                        gotoExternalInstruction));
             } else {
                 flow.setInstructions(instructions(applyActionIns(actionBuilderList),
                         (performNat == true) ? gotoEgressNatInstruction : gotoExternalInstruction));
@@ -923,30 +664,30 @@ public class PolicyEnforcer extends FlowTable {
         }
     }
 
-    private MatchBuilder createBaseMatch(Direction direction, PolicyPair policyPair, IpPrefix sIpPrefix,
-                                         IpPrefix dIpPrefix) {
+    private MatchBuilder createBaseMatch(Direction direction, NetworkElements netElements, IpPrefix sIpPrefix,
+            IpPrefix dIpPrefix) {
         MatchBuilder baseMatch = new MatchBuilder();
         if (direction.equals(Direction.In)) {
-            addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.consumerEpgId),
-                    RegMatch.of(NxmNxReg1.class, (long) policyPair.consumerCondGrpId),
-                    RegMatch.of(NxmNxReg2.class, (long) policyPair.providerEpgId),
-                    RegMatch.of(NxmNxReg3.class, (long) policyPair.providerCondGrpId));
+            addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) netElements.getDstEpOrdinals().getEpgId()),
+                    RegMatch.of(NxmNxReg1.class, (long) netElements.getDstEpOrdinals().getCgId()),
+                    RegMatch.of(NxmNxReg2.class, (long) netElements.getSrcEpOrdinals().getEpgId()),
+                    RegMatch.of(NxmNxReg3.class, (long) netElements.getSrcEpOrdinals().getCgId()));
             if (sIpPrefix != null) {
                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
             }
             if (dIpPrefix != null) {
-                baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
+                baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
             }
         } else {
-            addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.providerEpgId),
-                    RegMatch.of(NxmNxReg1.class, (long) policyPair.providerCondGrpId),
-                    RegMatch.of(NxmNxReg2.class, (long) policyPair.consumerEpgId),
-                    RegMatch.of(NxmNxReg3.class, (long) policyPair.consumerCondGrpId));
+            addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) netElements.getSrcEpOrdinals().getEpgId()),
+                    RegMatch.of(NxmNxReg1.class, (long) netElements.getSrcEpOrdinals().getCgId()),
+                    RegMatch.of(NxmNxReg2.class, (long) netElements.getDstEpOrdinals().getEpgId()),
+                    RegMatch.of(NxmNxReg3.class, (long) netElements.getDstEpOrdinals().getCgId()));
             if (sIpPrefix != null) {
                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
             }
             if (dIpPrefix != null) {
-                baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
+                baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
             }
         }
         return baseMatch;
@@ -970,7 +711,7 @@ public class PolicyEnforcer extends FlowTable {
 
     // TODO: move to a common utils for all renderers
     private List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
-                                                                                                         Endpoint consEp, Endpoint provEp) {
+            Endpoint consEp, Endpoint provEp) {
         List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
             EndpointConstraint consEpConstraint = cell.getRowKey();
@@ -990,12 +731,6 @@ public class PolicyEnforcer extends FlowTable {
         return constraint.getConditionSet().matches(epConditions);
     }
 
-    private enum PathStatus { both, partial, none }
-
-    public static boolean checkPolicyOrientation() {
-        return isReversedPolicy;
-    }
-
     /**
      * Private internal class for ordering Actions in Rules. The order is
      * determined first by the value of the order parameter, with the lower
@@ -1009,205 +744,23 @@ public class PolicyEnforcer extends FlowTable {
         @Override
         public int compare(ActionRef arg0, ActionRef arg1) {
             return ComparisonChain.start()
-                    .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
-                    .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
-                    .result();
+                .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
+                .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
+                .result();
         }
 
     }
 
-    @Immutable
-    public static class PolicyPair {
-
-        private final int consumerEpgId;
-        private final int providerEpgId;
-        private final int consumerCondGrpId;
-        private final int providerCondGrpId;
-        private final Set<IpPrefix> consumerEicIpPrefixes;
-        private final Set<IpPrefix> providerEicIpPrefixes;
-        private final NodeId consumerEpNodeId;
-        private final NodeId providerEpNodeId;
-
-        public PolicyPair(int consumerEpgId, int providerEpgId, int consumerCondGrpId, int providerCondGrpId,
-                          Set<IpPrefix> consumerEicIpPrefixes, Set<IpPrefix> providerEicIpPrefixes, NodeId consumerEpNodeId, NodeId providerEpNodeId) {
-            super();
-            this.consumerEpgId = consumerEpgId;
-            this.providerEpgId = providerEpgId;
-            this.consumerCondGrpId = consumerCondGrpId;
-            this.providerCondGrpId = providerCondGrpId;
-            this.consumerEicIpPrefixes = consumerEicIpPrefixes;
-            this.providerEicIpPrefixes = providerEicIpPrefixes;
-            this.consumerEpNodeId = consumerEpNodeId;
-            this.providerEpNodeId = providerEpNodeId;
-        }
-
-        public int getConsumerEpgId() {
-            return consumerEpgId;
-        }
-
-        public int getProviderEpgId() {
-            return providerEpgId;
-        }
-
-        public NodeId getConsumerEpNodeId() {
-            return consumerEpNodeId;
-        }
-
-        public NodeId getProviderEpNodeId() {
-            return providerEpNodeId;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((providerEicIpPrefixes == null) ? 0 : providerEicIpPrefixes.hashCode());
-            result = prime * result + providerCondGrpId;
-            result = prime * result + providerEpgId;
-            result = prime * result + ((consumerEicIpPrefixes == null) ? 0 : consumerEicIpPrefixes.hashCode());
-            result = prime * result + consumerCondGrpId;
-            result = prime * result + consumerEpgId;
-            result = prime * result + ((consumerEpNodeId == null) ? 0 : consumerEpNodeId.hashCode());
-            result = prime * result + ((providerEpNodeId == null) ? 0 : providerEpNodeId.hashCode());
-
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            PolicyPair other = (PolicyPair) obj;
-            if (providerEicIpPrefixes == null) {
-                if (other.providerEicIpPrefixes != null) {
-                    return false;
-                }
-            } else if (!providerEicIpPrefixes.equals(other.providerEicIpPrefixes)) {
-                return false;
-            }
-            if (consumerEicIpPrefixes == null) {
-                if (other.consumerEicIpPrefixes != null) {
-                    return false;
-                }
-            } else if (!consumerEicIpPrefixes.equals(other.consumerEicIpPrefixes)) {
-                return false;
-            }
-            if (consumerEpNodeId == null) {
-                if (other.consumerEpNodeId != null) {
-                    return false;
-                }
-            } else if (!consumerEpNodeId.getValue().equals(other.consumerEpNodeId.getValue())) {
-                return false;
-            }
-            if (providerEpNodeId == null) {
-                if (other.providerEpNodeId != null) {
-                    return false;
-                }
-            } else if (!providerEpNodeId.getValue().equals(other.providerEpNodeId.getValue())) {
-                return false;
-            }
-            return (providerCondGrpId == other.providerCondGrpId)
-                    && (providerEpgId == other.providerEpgId)
-                    && (consumerCondGrpId == other.consumerCondGrpId)
-                    && (consumerEpgId == other.consumerEpgId);
-
-        }
+    private static class RuleGroupComparator implements Comparator<RuleGroup> {
 
         @Override
-        public String toString() {
-            return "consumerEPG: " + consumerEpgId +
-                    "consumerCG: " + consumerCondGrpId +
-                    "providerEPG: " + providerEpgId +
-                    "providerCG: " + providerCondGrpId +
-                    "consumerEpNodeId: " + consumerEpNodeId +
-                    "providerEpNodeId: " + providerEpNodeId +
-                    "consumerEicIpPrefixes: " + consumerEicIpPrefixes +
-                    "providerEicIpPrefixes: " + providerEicIpPrefixes;
-        }
-    }
-
-    public class NetworkElements {
-
-        private final Endpoint srcEp;
-        private final Endpoint dstEp;
-        private final EgKey srcEpg;
-        private final EgKey dstEpg;
-        private NodeId srcNodeId;
-        private NodeId dstNodeId;
-        private final NodeId localNodeId;
-        private EndpointFwdCtxOrdinals srcEpOrdinals;
-        private EndpointFwdCtxOrdinals dstEpOrdinals;
-
-        public NetworkElements(Endpoint srcEp, Endpoint dstEp, EgKey srcEpg, EgKey dstEpg, NodeId nodeId, OfContext ctx) throws Exception {
-            this.srcEp = srcEp;
-            this.dstEp = dstEp;
-            this.srcEpg = srcEpg;
-            this.dstEpg = dstEpg;
-            this.localNodeId = nodeId;
-            this.srcEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);
-            if (this.srcEpOrdinals == null) {
-                LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
-                return;
-            }
-            this.dstEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
-            if (this.dstEpOrdinals == null) {
-                LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
-                return;
-            }
-            if (dstEp.getAugmentation(OfOverlayContext.class) != null) {
-                this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();
-            }
-            if (srcEp.getAugmentation(OfOverlayContext.class) != null) {
-                this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();
-            }
-        }
-
-
-        public Endpoint getSrcEp() {
-            return srcEp;
-        }
-
-
-        public Endpoint getDstEp() {
-            return dstEp;
-        }
-
-        public EgKey getSrcEpg() {
-            return srcEpg;
-        }
-
-        public EgKey getDstEpg() {
-            return dstEpg;
-        }
-
-        public NodeId getSrcNodeId() {
-            return srcNodeId;
-        }
-
-
-        public NodeId getDstNodeId() {
-            return dstNodeId;
-        }
-
-
-        public NodeId getLocalNodeId() {
-            return localNodeId;
-        }
-
-
-        public EndpointFwdCtxOrdinals getSrcEpOrdinals() {
-            return srcEpOrdinals;
-        }
-
-
-        public EndpointFwdCtxOrdinals getDstEpOrdinals() {
-            return dstEpOrdinals;
+        public int compare(RuleGroup arg0, RuleGroup arg1) {
+            return ComparisonChain.start()
+                .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
+                .compare(arg0.getRelatedSubject().getValue(), arg1.getRelatedSubject().getValue()
+                        ,Ordering.natural().nullsLast())
+                .result();
         }
 
-
     }
 }
index 47c7ac20d134d874cc8080285423b6ad13bf30a3..7ed357a6a76e8e78c0b4334ac2004c0295e3234f 100755 (executable)
@@ -14,8 +14,7 @@ import java.util.Map;
 import org.opendaylight.groupbasedpolicy.api.Validator;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.NetworkElements;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.PolicyPair;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements;
 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.policy.rev140421.HasDirection.Direction;
@@ -43,7 +42,7 @@ public abstract class Action implements Validator<ActionInstance> {
 
     /**
      * The result represents supported parameters for the action by renderer
-     * 
+     *
      * @return list of supported parameters by the action
      */
     public abstract List<SupportedParameterValues> getSupportedParameterValues();
@@ -57,7 +56,6 @@ public abstract class Action implements Validator<ActionInstance> {
      * @param params the parameters for the action instance
      * @param order the order of the list of actions
      * @param netElements the network elements
-     * @param policyPair the {@link PolicyPair}
      * @param ofWriter the {@link OfWriter}
      * @param ctx the OfContext
      * @param direction the direction of traffic
@@ -67,7 +65,6 @@ public abstract class Action implements Validator<ActionInstance> {
                                                      Map<String, Object> params,
                                                      Integer order,
                                                      NetworkElements netElements,
-                                                     PolicyPair policyPair,
                                                      OfWriter ofWriter,
                                                      OfContext ctx,
                                                      Direction direction);
index 727fe76961c66c9f1953ba675ffdfec21fb13641..f2c0fa8249b57418b3ad3bbe2cc9bf9721a702fb 100755 (executable)
@@ -19,8 +19,7 @@ import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
 import org.opendaylight.groupbasedpolicy.dto.ValidationResultBuilder;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.NetworkElements;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.PolicyPair;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements;
 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.policy.rev140421.HasDirection.Direction;
@@ -52,7 +51,6 @@ public class AllowAction extends Action {
                                             Map<String, Object> params,
                                             Integer order,
                                             NetworkElements netElements,
-                                            PolicyPair policyPair,
                                             OfWriter ofWriter,
                                             OfContext ctx,
                                             Direction direction) {
index 8ee0c2c30cdc5de6dae802623718fff30791cecc..ad001954b056692772ebabd30d1aa48cc1273216 100755 (executable)
@@ -12,6 +12,7 @@ import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.ChainAct
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNsiAction;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNspAction;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -22,9 +23,7 @@ import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
 import org.opendaylight.groupbasedpolicy.dto.ValidationResultBuilder;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.NetworkElements;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.PolicyPair;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements;
 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;
@@ -73,6 +72,11 @@ import com.google.common.collect.Iterables;
 public class ChainAction extends Action {
 
     private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
+    private List<String> resolvedSymmetricChains = new ArrayList<>();;
+
+    public void setResolvedSymmetricChains(List<String> resolvedSymmetricChains) {
+        this.resolvedSymmetricChains = resolvedSymmetricChains;
+    }
 
     @Override
     public ActionDefinitionId getId() {
@@ -86,7 +90,7 @@ public class ChainAction extends Action {
 
     @Override
     public List<ActionBuilder> updateAction(List<ActionBuilder> actions, Map<String, Object> params, Integer order,
-                                            NetworkElements netElements, PolicyPair policyPair, OfWriter ofWriter,
+                                            NetworkElements netElements, OfWriter ofWriter,
                                             OfContext ctx, Direction direction) {
         /*
          * Get the named chain
@@ -113,7 +117,7 @@ public class ChainAction extends Action {
             return null;
         }
 
-        Long returnVnId;
+        Long tunnelId;
 
         /*
          * If path is symmetrical then there are two RSPs.
@@ -134,7 +138,7 @@ public class ChainAction extends Action {
         ReadOnlyTransaction rTx = ctx.getDataBroker().newReadOnlyTransaction();
         RenderedServicePath renderedServicePath;
         RenderedServicePath rsp = getRspByName(rspName, rTx);
-        returnVnId = (long) resolveTunnelId(netElements, false);
+        tunnelId = (long) netElements.getSrcEpOrdinals().getTunnelId();
         if (rsp == null) {
             renderedServicePath = createRsp(sfcPath, rspName);
             if (renderedServicePath != null) {
@@ -148,10 +152,10 @@ public class ChainAction extends Action {
         }
 
         try {
-            if (sfcPath.isSymmetric() && direction.equals(Direction.Out)) {
+        if (sfcPath.isSymmetric() && resolvedSymmetricChains.contains(chainName)) {
                 rspName = new RspName(rspName.getValue() + "-Reverse");
                 rsp = getRspByName(rspName, rTx);
-                returnVnId = (long) resolveTunnelId(netElements, true);
+                tunnelId = (long) netElements.getDstEpOrdinals().getTunnelId();
                 if (rsp == null) {
                     LOG.info("updateAction: Could not find Reverse RSP {} for Chain {}", rspName, chainName);
                     renderedServicePath = createSymmetricRsp(renderedServicePath);
@@ -192,27 +196,18 @@ public class ChainAction extends Action {
             .setNshNsiFromChain((short) (lastRspHop.getServiceIndex().intValue() - 1))
             .setNshNspFromChain(renderedServicePath.getPathId())
             .setNshMetaC1(SfcNshHeader.convertIpAddressToLong(tunnelDest.getIpv4Address()))
-            .setNshMetaC2(returnVnId)
+            .setNshMetaC2(tunnelId)
             .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;
-    }
+        createChainTunnelFlows(sfcNshHeader, netElements, ofWriter, ctx, direction);
 
-    // Return tunnelId according to policy direction
-    private int resolveTunnelId(NetworkElements netElements, boolean isReversedPath) {
-        if ((isReversedPath && PolicyEnforcer.checkPolicyOrientation())
-                || (!isReversedPath && !PolicyEnforcer.checkPolicyOrientation())) {
-            return netElements.getDstEpOrdinals().getTunnelId();
+        if (direction.equals(Direction.Out) ) {
+            actions = addActionBuilder(actions, nxSetNsiAction(sfcNshHeader.getNshNsiToChain()), order);
+            actions = addActionBuilder(actions, nxSetNspAction(sfcNshHeader.getNshNspToChain()), order);
         } else {
-            return netElements.getSrcEpOrdinals().getTunnelId();
+            return null;
         }
+        return actions;
     }
 
     private RenderedServicePath createRsp(ServiceFunctionPath sfcPath, RspName rspName) {
@@ -288,7 +283,7 @@ public class ChainAction extends Action {
         }
     }
 
-    public ServiceFunctionPath getSfcPath(SfcName chainName) {
+    public static ServiceFunctionPath getSfcPath(SfcName chainName) {
         ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
         for (ServiceFunctionPath path : paths.getServiceFunctionPath()) {
             if (path.getServiceChainName().equals(chainName)) {
@@ -324,5 +319,4 @@ public class ChainAction extends Action {
         return ImmutableList.<SupportedParameterValues>of(new SupportedParameterValuesBuilder()
             .setParameterName(new ParameterName(ChainActionDefinition.SFC_CHAIN_NAME)).build());
     }
-
 }
index 8da0bbf458557816a684b8cb74282a6253c489b3..0957f00b66aeb7c80d4e19400383ef5ae33cd185 100644 (file)
@@ -18,7 +18,7 @@ import org.junit.Before;
 import org.junit.Test;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;\r
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.NetworkElements;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader.SfcNshHeaderBuilder;\r
index 880a6c9e62051a82a46279569a31e4337ba9a0e9..efb4160cd38814661daa254e60386785ba96352a 100755 (executable)
@@ -13,11 +13,11 @@ import java.util.Map;
 import org.junit.Ignore;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
 \r
 public class FlowTableTest extends OfTableTest {\r
-    FlowTable table;\r
+    protected FlowTable table;\r
     InstanceIdentifier<Table> tiid;\r
 \r
     protected void setup() throws Exception {\r
index 182421b0232e96771c49f00ecbb3768f231c19d2..07e356ada4072313ef89f7814aa6b84d1e9db291 100755 (executable)
@@ -27,7 +27,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;\r
@@ -52,10 +51,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ForwardingContextBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.PolicyBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomainBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3ContextBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ContractBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroupBuilder;\r
@@ -75,31 +72,31 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import com.google.common.collect.ImmutableList;\r
 \r
 public class OfTableTest {\r
-    MockOfContext ctx;\r
+    protected MockOfContext ctx;\r
 \r
-    MockEndpointManager endpointManager;\r
-    MockPolicyManager policyManager;\r
-    MockSwitchManager switchManager;\r
-    NodeId nodeId = new NodeId("openflow:1");\r
-    NodeId remoteNodeId = new NodeId("openflow:2");\r
-    NodeConnectorId nodeConnectorId =\r
+    protected MockEndpointManager endpointManager;\r
+    protected MockPolicyManager policyManager;\r
+    protected MockSwitchManager switchManager;\r
+    protected NodeId nodeId = new NodeId("openflow:1");\r
+    protected NodeId remoteNodeId = new NodeId("openflow:2");\r
+    protected NodeConnectorId nodeConnectorId =\r
             new NodeConnectorId(nodeId.getValue() + ":4");\r
 \r
-    NodeConnectorId tunnelId =\r
+    protected NodeConnectorId tunnelId =\r
             new NodeConnectorId(nodeId.getValue() + ":42");\r
 \r
-    L3ContextId l3c = new L3ContextId("2cf51ee4-e996-467e-a277-2d380334a91d");\r
-    L2BridgeDomainId bd = new L2BridgeDomainId("c95182ba-7807-43f8-98f7-6c7c720b7639");\r
-    L2FloodDomainId fd = new L2FloodDomainId("98e1439e-52d2-46f8-bd69-5136e6088771");\r
-    L2FloodDomainId ext_fd = new L2FloodDomainId("d8024f7a-b83e-11e5-9912-ba0be0483c18");\r
-    SubnetId sub = new SubnetId("4fcf8dfc-53b5-4aef-84d3-6b5586992fcb");\r
-    SubnetId sub2 = new SubnetId("c285a59f-fcb8-42e6-bf29-87ea522fd626");\r
-    SubnetId sub3 = new SubnetId("a0380d52-2a25-48ef-882c-a4d4cd9e00ec");\r
-    SubnetId ext_sub = new SubnetId("8da17ad9-3261-4dc9-bcff-928a2f73cce7");\r
-    TenantId tid = new TenantId("1118c691-8520-47ad-80b8-4cf5e3fe3302");\r
-    EndpointGroupId eg = new EndpointGroupId("36dec84a-08c7-497b-80b6-a0035af72a12");\r
-    EndpointGroupId eg2 = new EndpointGroupId("632e5e11-7988-4eb5-8fe6-6c182d890276");\r
-    ContractId cid = new ContractId("a5874893-bcd5-46de-96af-3c8d99bedf9f");\r
+    protected L3ContextId l3c = new L3ContextId("2cf51ee4-e996-467e-a277-2d380334a91d");\r
+    protected L2BridgeDomainId bd = new L2BridgeDomainId("c95182ba-7807-43f8-98f7-6c7c720b7639");\r
+    protected L2FloodDomainId fd = new L2FloodDomainId("98e1439e-52d2-46f8-bd69-5136e6088771");\r
+    protected L2FloodDomainId ext_fd = new L2FloodDomainId("d8024f7a-b83e-11e5-9912-ba0be0483c18");\r
+    protected SubnetId sub = new SubnetId("4fcf8dfc-53b5-4aef-84d3-6b5586992fcb");\r
+    protected SubnetId sub2 = new SubnetId("c285a59f-fcb8-42e6-bf29-87ea522fd626");\r
+    protected SubnetId sub3 = new SubnetId("a0380d52-2a25-48ef-882c-a4d4cd9e00ec");\r
+    protected SubnetId ext_sub = new SubnetId("8da17ad9-3261-4dc9-bcff-928a2f73cce7");\r
+    protected TenantId tid = new TenantId("1118c691-8520-47ad-80b8-4cf5e3fe3302");\r
+    protected EndpointGroupId eg = new EndpointGroupId("36dec84a-08c7-497b-80b6-a0035af72a12");\r
+    protected EndpointGroupId eg2 = new EndpointGroupId("632e5e11-7988-4eb5-8fe6-6c182d890276");\r
+    protected ContractId cid = new ContractId("a5874893-bcd5-46de-96af-3c8d99bedf9f");\r
 \r
     protected void initCtx() {\r
         endpointManager = new MockEndpointManager();\r
index 64a8a61e510e3c4b58d2ec99e042ebd94ca516ad..644f4d1e9ecf311b07616d603e333828ca1f5a29 100644 (file)
@@ -1,15 +1,24 @@
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.dto.PolicyInfo;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
 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.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -17,9 +26,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
@@ -33,15 +50,25 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.Segmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.SegmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValueBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ForwardingContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.PolicyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3ContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.SubjectFeatureInstancesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ConsumerNamedSelectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ProviderNamedSelectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstanceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 
-import java.util.ArrayList;
-import java.util.List;
+import com.google.common.collect.ImmutableList;
 
 public abstract class MapperUtilsTest {
 
@@ -58,9 +85,24 @@ public abstract class MapperUtilsTest {
     protected static final String DHCP_IP = "255.255.255.255";
     protected static final String TENANT_ID = "dummy tenant";
     protected static final String NODE_ID = "dummy node";
+    protected static final String CONTRACT_ID = "dummy contract";
     protected static final String L2 = "L2";
-    private static final String DOMAIN_ID = "dummy id";
+    protected static final String DOMAIN_ID = "dummy id";
     protected final NodeId nodeId = new NodeId(NODE_ID);
+    protected NodeConnectorId nodeConnectorId =
+            new NodeConnectorId(nodeId.getValue() + CONNECTOR_0);
+    protected L3ContextId l3c = new L3ContextId("2cf51ee4-e996-467e-a277-2d380334a91d");
+    protected L2BridgeDomainId bd = new L2BridgeDomainId("c95182ba-7807-43f8-98f7-6c7c720b7639");
+    protected L2FloodDomainId fd = new L2FloodDomainId("98e1439e-52d2-46f8-bd69-5136e6088771");
+    protected L2FloodDomainId ext_fd = new L2FloodDomainId("d8024f7a-b83e-11e5-9912-ba0be0483c18");
+    protected SubnetId sub = new SubnetId("4fcf8dfc-53b5-4aef-84d3-6b5586992fcb");
+    protected SubnetId sub2 = new SubnetId("c285a59f-fcb8-42e6-bf29-87ea522fd626");
+    protected SubnetId sub3 = new SubnetId("a0380d52-2a25-48ef-882c-a4d4cd9e00ec");
+    protected SubnetId ext_sub = new SubnetId("8da17ad9-3261-4dc9-bcff-928a2f73cce7");
+    protected TenantId tid = new TenantId(TENANT_ID);
+    protected EndpointGroupId eg = new EndpointGroupId("36dec84a-08c7-497b-80b6-a0035af72a12");
+    protected EndpointGroupId eg2 = new EndpointGroupId("632e5e11-7988-4eb5-8fe6-6c182d890276");
+    protected ContractId cid = new ContractId("a5874893-bcd5-46de-96af-3c8d99bedf9f");
     protected Short tableId;
     protected OfContext ctx;
     protected OfWriter ofWriter;
@@ -68,6 +110,7 @@ public abstract class MapperUtilsTest {
     protected PolicyManager policyManager;
     protected EndpointManager endpointManager;
     protected PolicyInfo policyInfo;
+    protected FlowTable table;
 
     protected Flow flowCreator(FlowId flowId, short tableId, Integer priority, Match match, Instructions instructions) {
         FlowBuilder flowBuilder = FlowUtils.base(tableId);
@@ -100,6 +143,7 @@ public abstract class MapperUtilsTest {
         // Augment node connector
         OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder();
         ofOverlayContextBuilder.setNodeConnectorId(new NodeConnectorId(nodeConnectorId));
+        ofOverlayContextBuilder.setNodeId(nodeId);
         endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build());
 
         // Set network containment
@@ -176,4 +220,135 @@ public abstract class MapperUtilsTest {
         l2FloodDomains.add(l2FloodDomainBuilder.build());
         return l2FloodDomains;
     }
+
+    protected EndpointBuilder endpointBuilder(IpAddress ip, MacAddress mac, NodeConnectorId nodeConnectorId,
+            EndpointGroupId epg, L2BridgeDomainId l2) {
+        EndpointBuilder endpointBuilder = new EndpointBuilder();
+
+        // Set tenant
+        endpointBuilder.setTenant(new TenantId(TENANT_ID));
+
+        // Set L3 address
+        if (ip != null) {
+            List<L3Address> l3Addresses = new ArrayList<>();
+            L3AddressBuilder l3AddressBuilder = new L3AddressBuilder();
+            l3AddressBuilder.setIpAddress(ip);
+            l3Addresses.add(l3AddressBuilder.build());
+            endpointBuilder.setL3Address(l3Addresses);
+        }
+
+        // Set Mac address
+        endpointBuilder.setMacAddress(new MacAddress(mac));
+        endpointBuilder.setL2Context(l2);
+        endpointBuilder.setEndpointGroup(epg);
+
+        // Augment node connector
+        OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder();
+        ofOverlayContextBuilder.setNodeConnectorId(new NodeConnectorId(nodeConnectorId));
+        ofOverlayContextBuilder.setNodeId(nodeId);
+        endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build());
+
+        // Set network containment
+        endpointBuilder.setNetworkContainment(new NetworkDomainId(DOMAIN_ID));
+
+        return endpointBuilder;
+    }
+
+    protected TenantBuilder baseTenant() {
+        return new TenantBuilder().setId(tid)
+            .setPolicy(new PolicyBuilder()
+                .setEndpointGroup(ImmutableList.of(
+                        new EndpointGroupBuilder().setId(eg)
+                            .setNetworkDomain(sub)
+                            .setConsumerNamedSelector(ImmutableList.of(new ConsumerNamedSelectorBuilder()
+                                .setName(new SelectorName("cns1")).setContract(ImmutableList.of(cid)).build()))
+                            .build(),
+                        new EndpointGroupBuilder().setId(eg2)
+                            .setNetworkDomain(sub2)
+                            .setProviderNamedSelector(ImmutableList.of(new ProviderNamedSelectorBuilder()
+                                .setName(new SelectorName("pns1")).setContract(ImmutableList.of(cid)).build()))
+                            .build()))
+                .setSubjectFeatureInstances(
+                        new SubjectFeatureInstancesBuilder()
+                            .setClassifierInstance(
+                                    ImmutableList
+                                        .of(new ClassifierInstanceBuilder().setName(new ClassifierName("tcp_dst_80"))
+                                            .setClassifierDefinitionId(L4ClassifierDefinition.DEFINITION.getId())
+                                            .setParameterValue(ImmutableList.of(
+                                                    new ParameterValueBuilder().setName(new ParameterName("destport"))
+                                                        .setIntValue(Long.valueOf(80))
+                                                        .build(),
+                                                    new ParameterValueBuilder().setName(new ParameterName("proto"))
+                                                        .setIntValue(Long.valueOf(6))
+                                                        .build()))
+                                            .build(), new ClassifierInstanceBuilder()
+                                                .setName(new ClassifierName("tcp_src_80"))
+                                                .setClassifierDefinitionId(Classifier.L4_CL.getId())
+                                                .setParameterValue(ImmutableList.of(
+                                                        new ParameterValueBuilder()
+                                                            .setName(new ParameterName("sourceport"))
+                                                            .setIntValue(Long.valueOf(80))
+                                                            .build(),
+                                                        new ParameterValueBuilder().setName(new ParameterName("proto"))
+                                                            .setIntValue(Long.valueOf(6))
+                                                            .build()))
+                                                .build(),
+                                                new ClassifierInstanceBuilder()
+                                                    .setName(new ClassifierName("ether_type"))
+                                                    .setClassifierDefinitionId(Classifier.ETHER_TYPE_CL.getId())
+                                                    .setParameterValue(ImmutableList.of(new ParameterValueBuilder()
+                                                        .setName(new ParameterName("ethertype"))
+                                                        .setIntValue(Long.valueOf(FlowUtils.IPv4))
+                                                        .build()))
+                                                    .build()))
+                            .setActionInstance(
+                                    ImmutableList.of(new ActionInstanceBuilder().setName(new ActionName("allow"))
+                                        .setActionDefinitionId(new AllowAction().getId())
+                                        .build()))
+                            .build())
+                .build())
+            .setForwardingContext(
+                    new ForwardingContextBuilder()
+                        .setL3Context(ImmutableList.of(new L3ContextBuilder().setId(l3c).build()))
+                        .setL2BridgeDomain(
+                                ImmutableList.of(new L2BridgeDomainBuilder().setId(bd).setParent(l3c).build()))
+                        .setL2FloodDomain(ImmutableList.of(
+                                new L2FloodDomainBuilder()
+                                    .setId(fd)
+                                    .setParent(bd)
+                                    .addAugmentation(Segmentation.class,
+                                        new SegmentationBuilder()
+                                        .setSegmentationId(Integer.valueOf(216))
+                                        .build())
+                                    .build(),
+                                new L2FloodDomainBuilder()
+                                    .setId(ext_fd)
+                                    .addAugmentation(Segmentation.class,
+                                        new SegmentationBuilder()
+                                        .setSegmentationId(Integer.valueOf(2016))
+                                        .build())
+                                    .build()))
+                        .setSubnet(ImmutableList.of(
+                                new SubnetBuilder().setId(sub2)
+                                    .setParent(fd)
+                                    .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.1.0/24")))
+                                    .setVirtualRouterIp(new IpAddress(new Ipv4Address("10.0.1.1")))
+                                    .build(),
+                                new SubnetBuilder().setId(sub)
+                                    .setParent(fd)
+                                    .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.0.0/24")))
+                                    .setVirtualRouterIp(new IpAddress(new Ipv4Address("10.0.0.1")))
+                                    .build(),
+                                new SubnetBuilder().setId(sub3)
+                                    .setParent(bd)
+                                    .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.2.0/24")))
+                                    .setVirtualRouterIp(new IpAddress(new Ipv4Address("10.0.2.1")))
+                                    .build(),
+                                new SubnetBuilder()
+                                    .setId(ext_sub)
+                                    .setIpPrefix(new IpPrefix(new Ipv4Prefix("192.168.111.0/24")))
+                                    .setParent(ext_fd)
+                                    .build()))
+                       .build());
+    }
 }
@@ -6,44 +6,46 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.junit.Assert.assertTrue;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 
-import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.opendaylight.groupbasedpolicy.dto.ConditionGroup;
 import org.opendaylight.groupbasedpolicy.dto.EgKey;
 import org.opendaylight.groupbasedpolicy.dto.PolicyInfo;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockOfContext;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockPolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.MockEndpointManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.PolicyPair;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.MapperUtilsTest;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.MockSwitchManager;
 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.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionMatcherName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
@@ -54,6 +56,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Matcher.MatchType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcherBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.ConditionBuilder;
@@ -62,12 +66,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ContractBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.ClauseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.Subject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.SubjectBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.ConsumerMatchersBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.ProviderMatchersBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.RuleBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
@@ -91,18 +95,33 @@ import com.google.common.collect.ImmutableMap;
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({PolicyManager.class})
-public class PolicyEnforcerTest extends FlowTableTest {
-
-    @Override
+public class PolicyEnforcerTest extends MapperUtilsTest {
+
+    //TODO (att: kblagov) XXX needs redesign
+    private final int sameEpgFlows = 1;
+    private final int allowTunnelFlows = 1;
+    private final int layer4flowsIPv4 = 1;
+    private final int layer4flowsIPv6 = 1;
+    private final int dropAllFlow = 1;
+    private final int arpFlows = 1;
+    private MockEndpointManager endpointManagerMock;
+    private MockPolicyManager policyManagerMock;
+    private MockSwitchManager switchManagerMock;
+    private MockOfContext ctxMock;
+
+    private NodeConnectorId tunnelId =
+            new NodeConnectorId(nodeId.getValue() + ":42");
     @Before
     public void setup() throws Exception {
         PowerMockito.stub(PowerMockito.method(PolicyManager.class, "setSfcTableOffset")).toReturn(true);
 
-        initCtx();
-        table = new PolicyEnforcer(ctx, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER());
-        super.setup();
+        endpointManagerMock = new MockEndpointManager();
+        policyManagerMock = new MockPolicyManager(endpointManagerMock);
+        switchManagerMock = new MockSwitchManager();
+        ctxMock = new MockOfContext(null, policyManagerMock, switchManagerMock, endpointManagerMock, null);
+        table = new PolicyEnforcer(ctxMock, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER());
 
-        switchManager.addSwitch(
+        switchManagerMock.addSwitch(
                 nodeId,
                 tunnelId,
                 Collections.<NodeConnectorId>emptySet(),
@@ -113,57 +132,49 @@ public class PolicyEnforcerTest extends FlowTableTest {
                             .build())).build());
     }
 
-    @Ignore
-    @Test
-    public void testNoEps() throws Exception {
-        OfWriter fm = dosync(null);
-        assertEquals(2, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
-            .getFlow()
-            .size());
-    }
-
-    @Ignore
     @Test
     public void testSameEg() throws Exception {
-        Endpoint ep1 = localEP().build();
-        endpointManager.addEndpoint(ep1);
-        Endpoint ep2 = localEP().setMacAddress(new MacAddress("00:00:00:00:00:02")).build();
-        endpointManager.addEndpoint(ep2);
-        ctx.addTenant(baseTenant().setPolicy(new PolicyBuilder(baseTenant().getPolicy())
+        Endpoint ep1 = endpointBuilder(new IpAddress(IPV4_1.toCharArray()), new MacAddress(MAC_0), nodeConnectorId, eg, bd)
+                .build();
+        endpointManagerMock.addEndpoint(ep1);
+        Endpoint ep2 = endpointBuilder(new IpAddress(IPV4_2.toCharArray()), new MacAddress(MAC_1), nodeConnectorId, eg, bd)
+                .build();
+        endpointManagerMock.addEndpoint(ep2);
+        ctxMock.addTenant(baseTenant().setPolicy(new PolicyBuilder(baseTenant().getPolicy())
             .setContract(ImmutableList.of(baseContract(null).build())).build()).build());
 
-        OfWriter fm = dosync(null);
-        assertNotEquals(0, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
+        ofWriter = new OfWriter();
+        table.sync(ep1, ofWriter);
+        assertTrue(!ofWriter.getTableForNode(nodeId, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER())
             .getFlow()
-            .size());
+            .isEmpty());
         int count = 0;
         HashMap<String, Flow> flowMap = new HashMap<>();
-        for (Flow f : fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()).getFlow()) {
+        for (Flow f : ofWriter.getTableForNode(nodeId, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER()).getFlow()) {
             flowMap.put(f.getId().getValue(), f);
             if (isAllowSameEpg(f)) {
                 count += 1;
             }
         }
-        assertEquals(1, count);
-        assertEquals(3, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
-            .getFlow()
-            .size());
-        fm = dosync(flowMap);
-        assertEquals(3, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
+        assertEquals(sameEpgFlows, count);
+        int totalFlows = sameEpgFlows + allowTunnelFlows + dropAllFlow;
+        assertEquals(totalFlows, ofWriter.getTableForNode(nodeId, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER())
             .getFlow()
             .size());
     }
 
-    @Ignore
     @Test
     public void testDifferentEg() throws Exception {
-        assertEquals(7, doTestDifferentEg(ImmutableList.of(baseSubject(null).build())));
-        assertEquals(7, doTestDifferentEg(ImmutableList.of(baseSubject(Direction.Bidirectional).build())));
-        assertEquals(5, doTestDifferentEg(ImmutableList.of(baseSubject(Direction.In).build())));
-        assertEquals(5, doTestDifferentEg(ImmutableList.of(baseSubject(Direction.Out).build())));
+        int totalFlows = sameEpgFlows + allowTunnelFlows;
+        assertEquals(totalFlows, doTestDifferentEg(ImmutableList.of(baseSubject(null).build())));
+        // one layer4 flow for each direction
+        totalFlows = sameEpgFlows + allowTunnelFlows + (2 * layer4flowsIPv4) + (2 * layer4flowsIPv6);
+        assertEquals(totalFlows, doTestDifferentEg(ImmutableList.of(baseSubject(Direction.Bidirectional).build())));
+        totalFlows = sameEpgFlows + allowTunnelFlows + layer4flowsIPv4 + layer4flowsIPv6;
+        assertEquals(totalFlows, doTestDifferentEg(ImmutableList.of(baseSubject(Direction.In).build())));
+        assertEquals(totalFlows, doTestDifferentEg(ImmutableList.of(baseSubject(Direction.Out).build())));
     }
 
-    @Ignore
     @Test
     public void doTestRule() throws Exception {
         Rule rule1 = new RuleBuilder().setActionRef(
@@ -191,30 +202,39 @@ public class PolicyEnforcerTest extends FlowTableTest {
                             Direction.In)))
             .build();
 
-        assertEquals(5,
+        int totalFlows = sameEpgFlows + allowTunnelFlows + layer4flowsIPv4 + layer4flowsIPv6;
+        assertEquals(totalFlows,
                 doTestDifferentEg(ImmutableList.of(createSubject("s1", ImmutableList.of(rule1)))));
-        assertEquals(11,
+        // one layer4 flow for each direction
+        totalFlows = sameEpgFlows + allowTunnelFlows + (2 * layer4flowsIPv4) + (2 * layer4flowsIPv6);
+        assertEquals(totalFlows,
                 doTestDifferentEg(ImmutableList.of(createSubject("s2", ImmutableList.of(rule2)))));
-        assertEquals(9,
+         // only one ether_type for out direction
+        totalFlows = sameEpgFlows + allowTunnelFlows + (2 * layer4flowsIPv4) + layer4flowsIPv6;
+        assertEquals(totalFlows,
                 doTestDifferentEg(ImmutableList.of(createSubject("s3", ImmutableList.of(rule3)))));
-        assertEquals(3,
+        totalFlows = sameEpgFlows + allowTunnelFlows;
+        assertEquals(totalFlows,
                 doTestDifferentEg(ImmutableList.of(createSubject("s4", ImmutableList.of(rule4)))));
     }
 
     private int doTestDifferentEg(List<Subject> subjects) throws Exception {
-        Endpoint ep1 = localEP().build();
-        endpointManager.addEndpoint(ep1);
-        Endpoint ep2 = localEP().setMacAddress(new MacAddress("00:00:00:00:00:02")).setEndpointGroup(eg2).build();
-        endpointManager.addEndpoint(ep2);
-        ctx.addTenant(baseTenant().setPolicy(new PolicyBuilder(baseTenant().getPolicy())
+        Endpoint ep1 = endpointBuilder(new IpAddress(IPV4_1.toCharArray()), new MacAddress(MAC_0), nodeConnectorId, eg, bd)
+                .build();
+        endpointManagerMock.addEndpoint(ep1);
+        Endpoint ep2 = endpointBuilder(new IpAddress(IPV4_2.toCharArray()), new MacAddress(MAC_1), nodeConnectorId, eg2, bd)
+                .build();
+        endpointManagerMock.addEndpoint(ep2);
+        ctxMock.addTenant(baseTenant().setPolicy(new PolicyBuilder(baseTenant().getPolicy())
             .setContract(ImmutableList.of(baseContract(subjects).build())).build()).build());
 
-        OfWriter fm = dosync(null);
-        assertNotEquals(0, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
+        ofWriter = new OfWriter();
+        table.sync(ep1, ofWriter);
+        assertTrue(!ofWriter.getTableForNode(nodeId, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER())
             .getFlow()
-            .size());
+            .isEmpty());
         int count = 0;
-        for (Flow f : fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()).getFlow()) {
+        for (Flow f : ofWriter.getTableForNode(nodeId, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER()).getFlow()) {
             if (isAllowSameEpg(f)) {
                 count += 1;
             } else if (f.getMatch() != null && Objects.equals(tunnelId, f.getMatch().getInPort())) {
@@ -255,19 +275,18 @@ public class PolicyEnforcerTest extends FlowTableTest {
         return count;
     }
 
-    @Ignore
     @Test
     public void testConditions() throws Exception {
         Condition cond1 = new ConditionBuilder().setName(new ConditionName("cond1")).build();
         Condition cond2 = new ConditionBuilder().setName(new ConditionName("cond2")).build();
 
-        Endpoint ep1 = localEP().setCondition(ImmutableList.of(cond1.getName())).build();
-        endpointManager.addEndpoint(ep1);
-        Endpoint ep2 = localEP().setMacAddress(new MacAddress("00:00:00:00:00:02"))
+        Endpoint ep1 = endpointBuilder(new IpAddress(IPV4_1.toCharArray()), new MacAddress(MAC_0), nodeConnectorId, eg, bd)
+                .setCondition(ImmutableList.of(cond1.getName())).build();
+        endpointManagerMock.addEndpoint(ep1);
+        Endpoint ep2 = endpointBuilder(new IpAddress(IPV4_2.toCharArray()), new MacAddress(MAC_1), nodeConnectorId, eg2, bd)
             .setCondition(ImmutableList.of(cond1.getName(), cond2.getName()))
-            .setEndpointGroup(eg2)
             .build();
-        endpointManager.addEndpoint(ep2);
+        endpointManagerMock.addEndpoint(ep2);
 
         TenantBuilder tb = baseTenant().setPolicy(new PolicyBuilder(baseTenant().getPolicy()).setContract(
                 ImmutableList.of(new ContractBuilder().setId(cid)
@@ -291,12 +310,12 @@ public class PolicyEnforcerTest extends FlowTableTest {
                                                     .build())).build())
                                 .build()))
                     .build())).build());
-        ctx.addTenant(tb.build());
+        ctxMock.addTenant(tb.build());
 
-        PolicyInfo policy = ctx.getCurrentPolicy();
-        List<ConditionName> ep1c = endpointManager.getConditionsForEndpoint(ep1);
+        PolicyInfo policy = ctxMock.getCurrentPolicy();
+        List<ConditionName> ep1c = endpointManagerMock.getConditionsForEndpoint(ep1);
         ConditionGroup cg1 = policy.getEgCondGroup(new EgKey(tb.getId(), ep1.getEndpointGroup()), ep1c);
-        List<ConditionName> ep2c = endpointManager.getConditionsForEndpoint(ep2);
+        List<ConditionName> ep2c = endpointManagerMock.getConditionsForEndpoint(ep2);
         ConditionGroup cg2 = policy.getEgCondGroup(new EgKey(tb.getId(), ep2.getEndpointGroup()), ep2c);
         int cg1Id = OrdinalFactory.getCondGroupOrdinal(cg1);
         int cg2Id = OrdinalFactory.getCondGroupOrdinal(cg2);
@@ -310,26 +329,23 @@ public class PolicyEnforcerTest extends FlowTableTest {
                 RegMatch.of(NxmNxReg1.class, (long) cg1Id), RegMatch.of(NxmNxReg2.class, (long) eg2Id),
                 RegMatch.of(NxmNxReg3.class, (long) cg2Id));
         int count = 0;
-        OfWriter fm = dosync(null);
-        assertEquals(7, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
+        ofWriter = new OfWriter();
+        table.sync(ep1, ofWriter);
+        // one layer4 flow for each direction
+        int totalFlows = sameEpgFlows + allowTunnelFlows + layer4flowsIPv4 + layer4flowsIPv6 + arpFlows + dropAllFlow;;
+        assertEquals(totalFlows, ofWriter.getTableForNode(nodeId, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER())
             .getFlow()
             .size());
         HashMap<String, Flow> flowMap = new HashMap<>();
-        for (Flow f : fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()).getFlow()) {
+        for (Flow f : ofWriter.getTableForNode(nodeId, ctxMock.getPolicyManager().getTABLEID_POLICY_ENFORCER()).getFlow()) {
             flowMap.put(f.getId().getValue(), f);
             if (f.getMatch() != null && f.getMatch().getEthernetMatch() != null) {
                 count++;
             }
         }
-        assertEquals(3, count);
-        fm = dosync(flowMap);
-        int numberOfFlows = fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
-            .getFlow()
-            .size();
-        fm = dosync(flowMap);
-        assertEquals(numberOfFlows, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER())
-            .getFlow()
-            .size());
+        //flows with ether_type match
+        totalFlows = layer4flowsIPv4 + layer4flowsIPv6 + arpFlows;
+        assertEquals(totalFlows, count);
     }
 
     private boolean isAllowSameEpg(Flow flow) {
@@ -367,100 +383,50 @@ public class PolicyEnforcerTest extends FlowTableTest {
         return res;
     }
 
-    PolicyPair policyPair;
-    int consumerEpgId;
-    int providerEpgId;
-    int consumerCondGrpId;
-    int providerCondGrpId;
-    Set<IpPrefix> consumerEicIpPrefixes;
-    Set<IpPrefix> providerEicIpPrefixes;
-    IpPrefix consumerEicIp;
-    IpPrefix providerEicIp;
-    NodeId consumerEpNodeId;
-    NodeId providerEpNodeId;
-
-    @Before
-    public void PolicyPairInitialisation() {
-        consumerEpgId = 5;
-        providerEpgId = 8;
-        consumerCondGrpId = 5;
-        providerCondGrpId = 8;
-        consumerEicIp = mock(IpPrefix.class);
-        providerEicIp = mock(IpPrefix.class);
-        consumerEicIpPrefixes = new HashSet<>(Collections.singletonList(consumerEicIp));
-        providerEicIpPrefixes = new HashSet<>(Collections.singletonList(providerEicIp));
-        consumerEpNodeId = mock(NodeId.class);
-        when(consumerEpNodeId.getValue()).thenReturn("consumerValue");
-        providerEpNodeId = mock(NodeId.class);
-        when(providerEpNodeId.getValue()).thenReturn("providerValue");
+    protected ContractBuilder baseContract(List<Subject> subjects) {
+        ContractBuilder contractBuilder = new ContractBuilder().setId(cid).setSubject(subjects);
+        // TODO refactor
+        if (subjects == null) {
+            return contractBuilder.setClause(ImmutableList.of(new ClauseBuilder().setName(new ClauseName("test"))
+                .setSubjectRefs(ImmutableList.<SubjectName>of(new SubjectName("s1")))
+                .build()));
+        }
+        List<SubjectName> subjectNames = new ArrayList<>();
+        for (Subject subject : subjects) {
+            subjectNames.add(subject.getName());
+        }
+        return contractBuilder.setClause(ImmutableList.of(new ClauseBuilder().setName(new ClauseName("test"))
+            .setSubjectRefs(subjectNames)
+            .build()));
     }
 
-    @Test
-    public void PolicyPairConstructorTest() {
-        policyPair = new PolicyPair(consumerEpgId, providerEpgId, consumerCondGrpId, providerCondGrpId,
-                consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId, providerEpNodeId);
-        Assert.assertEquals(consumerEpgId, policyPair.getConsumerEpgId());
-        Assert.assertEquals(providerEpgId, policyPair.getProviderEpgId());
-        Assert.assertEquals(consumerEpNodeId, policyPair.getConsumerEpNodeId());
-        Assert.assertEquals(providerEpNodeId, policyPair.getProviderEpNodeId());
-        Assert.assertNotNull(policyPair.toString());
+    protected SubjectBuilder baseSubject(Direction direction) {
+        return new SubjectBuilder()
+            .setName(new SubjectName("s1"))
+            .setRule(ImmutableList.of(new RuleBuilder()
+                .setActionRef(ImmutableList.of(new ActionRefBuilder()
+                    .setName(new ActionName("allow"))
+                    .build()))
+                .setClassifierRef(ImmutableList.of(new ClassifierRefBuilder()
+                    .setName(new ClassifierName("tcp_dst_80"))
+                    .setDirection(direction)
+                    .setInstanceName(new ClassifierName("tcp_dst_80"))
+                    .build()))
+                .build()));
     }
 
-    @Test
-    public void PolicyPairEqualsTest() {
-        policyPair = new PolicyPair(0, 0, 0, 0, null, null, null, null);
-        PolicyPair other;
-        other = new PolicyPair(0, 0, 0, 0, null, null, null, null);
-        Assert.assertTrue(policyPair.equals(other));
-
-        policyPair = new PolicyPair(consumerEpgId, providerEpgId, consumerCondGrpId, providerCondGrpId,
-                consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId, providerEpNodeId);
-
-        Assert.assertNotNull(policyPair);
-        Assert.assertFalse(policyPair.equals(new Object()));
-
-        Assert.assertFalse(other.equals(policyPair));
-        Assert.assertFalse(policyPair.equals(other));
-
-        other = new PolicyPair(0, 0, 0, 0, null, providerEicIpPrefixes, null, null);
-        Assert.assertFalse(other.equals(policyPair));
-        Assert.assertFalse(policyPair.equals(other));
-
-        other = new PolicyPair(0, 0, 0, 0, consumerEicIpPrefixes, providerEicIpPrefixes, null, null);
-        Assert.assertFalse(other.equals(policyPair));
-
-        other = new PolicyPair(0, 0, 0, 0, consumerEicIpPrefixes, providerEicIpPrefixes, providerEpNodeId, null);
-        Assert.assertFalse(policyPair.equals(other));
-
-        other = new PolicyPair(0, 0, 0, 0, consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId, null);
-        Assert.assertFalse(other.equals(policyPair));
-
-        other = new PolicyPair(0, 0, 0, 0, consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId,
-                consumerEpNodeId);
-        Assert.assertFalse(policyPair.equals(other));
-
-        other = new PolicyPair(0, 0, 0, 0, consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId,
-                providerEpNodeId);
-        Assert.assertFalse(other.equals(policyPair));
-        Assert.assertFalse(policyPair.equals(other));
-
-        other = new PolicyPair(0, 0, 0, 8, consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId,
-                providerEpNodeId);
-        Assert.assertFalse(other.equals(policyPair));
-        Assert.assertFalse(policyPair.equals(other));
-
-        other = new PolicyPair(0, 8, 0, 8, consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId,
-                providerEpNodeId);
-        Assert.assertFalse(other.equals(policyPair));
-        Assert.assertFalse(policyPair.equals(other));
-
-        other = new PolicyPair(0, 8, 5, 8, consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId,
-                providerEpNodeId);
-        Assert.assertFalse(other.equals(policyPair));
-        Assert.assertFalse(policyPair.equals(other));
+    protected Subject createSubject(String name, List<Rule> rules){
+        return new SubjectBuilder().setName(new SubjectName(name)).setRule(rules).build();
+    }
 
-        other = new PolicyPair(5, 8, 5, 8, consumerEicIpPrefixes, providerEicIpPrefixes, consumerEpNodeId,
-                providerEpNodeId);
-        Assert.assertTrue(policyPair.equals(other));
+    protected List<ClassifierRef> createClassifierRefs(Map<String, Direction> refNamesAndDirections) {
+        List<ClassifierRef> refs = new ArrayList<>();
+        for (String refName : refNamesAndDirections.keySet()) {
+            refs.add(new ClassifierRefBuilder().setName(new ClassifierName(refName))
+                .setDirection(refNamesAndDirections.get(refName))
+                .setInstanceName(new ClassifierName(refName))
+                .build());
+        }
+        return refs;
     }
 }
index 9abcaeadb4887fe9396829adc34d10adf79be7d7..9fde7121efe5f03ad5f0558296cd9f3c5e5aea0e 100755 (executable)
@@ -9,12 +9,11 @@
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -24,6 +23,7 @@ import java.util.Set;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -34,8 +34,7 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.NetworkElements;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.PolicyEnforcer.PolicyPair;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements;
 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.SfpName;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
@@ -47,10 +46,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
 
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(ChainAction.class)
 public class ChainActionTest {
 
     private ChainAction chainAction;
@@ -66,7 +70,6 @@ public class ChainActionTest {
     private NodeId nodeId;
     private EndpointFwdCtxOrdinals endpointFwdCtxOrdinals;
     private Endpoint endpoint;
-    private PolicyPair policyPair;
     private EndpointManager endpointManager;
     private EgKey egKey;
     private TenantId tenant = new TenantId("e09a2308-6ffa-40af-92a2-69f54b2cf3e4");
@@ -74,7 +77,7 @@ public class ChainActionTest {
     @SuppressWarnings("unchecked")
     @Before
     public void initialise() throws Exception {
-        chainAction = spy(new ChainAction());
+        chainAction = new ChainAction();
 
         sfcPath = mock(ServiceFunctionPath.class);
         when(sfcPath.getName()).thenReturn(new SfpName("sfcPathName"));
@@ -102,8 +105,6 @@ public class ChainActionTest {
         endpoint = mock(Endpoint.class);
         when(netElements.getSrcEp()).thenReturn(endpoint);
         when(netElements.getSrcEp().getTenant()).thenReturn(tenant);
-        policyPair = mock(PolicyPair.class);
-        when(policyPair.getConsumerEpgId()).thenReturn(Integer.valueOf(5));
 
         endpointManager = mock(EndpointManager.class);
         when(ctx.getEndpointManager()).thenReturn(endpointManager);
@@ -129,10 +130,12 @@ public class ChainActionTest {
         Integer order = Integer.valueOf(0);
         OfWriter ofWriter = mock(OfWriter.class);
 
-        doReturn(sfcPath).when(chainAction).getSfcPath(new SfcName(chainName));
+        PowerMockito.mockStatic(ChainAction.class);
+        when(ChainAction.getSfcPath(new SfcName(chainName))).thenReturn(sfcPath);
+        chainAction.setResolvedSymmetricChains(Collections.singletonList(chainName));
 
         List<ActionBuilder> result =
-                chainAction.updateAction(actions, params, order, netElements, policyPair, ofWriter, ctx, Direction.Out);
+                chainAction.updateAction(actions, params, order, netElements, ofWriter, ctx, Direction.Out);
         Assert.assertNull(result);
     }
 
@@ -144,7 +147,7 @@ public class ChainActionTest {
         OfWriter ofWriter = mock(OfWriter.class);
 
         List<ActionBuilder> result =
-                chainAction.updateAction(actions, null, order, netElements, policyPair, ofWriter, ctx, Direction.In);
+                chainAction.updateAction(actions, null, order, netElements, ofWriter, ctx, Direction.In);
         Assert.assertNull(result);
     }
 
@@ -156,10 +159,12 @@ public class ChainActionTest {
         params.put(ChainActionDefinition.SFC_CHAIN_NAME, null);
         Integer order = Integer.valueOf(0);
         NetworkElements netElements = mock(NetworkElements.class);
-        PolicyPair policyPair = mock(PolicyPair.class);
         OfWriter ofWriter = mock(OfWriter.class);
 
-        chainAction.updateAction(actions, params, order, netElements, policyPair, ofWriter, ctx, Direction.In);
+        List<ActionBuilder> result =
+                chainAction.updateAction(actions, params, order, netElements, ofWriter, ctx, Direction.In);
+
+        Assert.assertNull(result);
     }
 
     @Test
@@ -172,11 +177,12 @@ public class ChainActionTest {
         Integer order = Integer.valueOf(0);
         OfWriter ofWriter = mock(OfWriter.class);
 
-        doReturn(sfcPath).when(chainAction).getSfcPath(new SfcName(chainName));
+        PowerMockito.mockStatic(ChainAction.class);
+        when(ChainAction.getSfcPath(new SfcName(chainName))).thenReturn(sfcPath);
         when(sfcPath.getName()).thenReturn(null);
 
         List<ActionBuilder> result =
-                chainAction.updateAction(actions, params, order, netElements, policyPair, ofWriter, ctx, Direction.Out);
+                chainAction.updateAction(actions, params, order, netElements, ofWriter, ctx, Direction.Out);
         Assert.assertNull(result);
     }