Implement SFC integration
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / PolicyEnforcer.java
index b5b6844c9651eaca5d8d8429d60a7e6bf169ce5e..87a31eaf2e53b642ec7d6ad1f76611ed131b1b04 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -8,7 +8,14 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
+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.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -17,10 +24,16 @@ import java.util.Set;
 
 import javax.annotation.concurrent.Immutable;
 
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
+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.resolver.ConditionGroup;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
@@ -28,20 +41,24 @@ import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.resolver.Policy;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
+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;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+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.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
@@ -49,25 +66,26 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev14
 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.NxmNxReg2;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
 
 /**
- * Manage the table that enforces policy on the traffic.  Traffic is denied
+ * Manage the table that enforces policy on the traffic. Traffic is denied
  * unless specifically allowed by policy
- * @author readams
  */
 public class PolicyEnforcer extends FlowTable {
-    protected static final Logger LOG =
-            LoggerFactory.getLogger(PolicyEnforcer.class);
+
+    protected static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
 
     public static final short TABLE_ID = 3;
 
-    public PolicyEnforcer(OfTable.OfTableCtx ctx) {
+    public PolicyEnforcer(OfContext ctx) {
         super(ctx);
     }
 
@@ -77,245 +95,347 @@ public class PolicyEnforcer extends FlowTable {
     }
 
     @Override
-    public void sync(ReadWriteTransaction t, InstanceIdentifier<Table> tiid,
-                     Map<String, FlowCtx> flowMap, NodeId nodeId, 
-                     PolicyInfo policyInfo, Dirty dirty)
-                             throws Exception {
-        dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
-        allowFromTunnel(t, tiid, flowMap, nodeId);
+    public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
+
+        flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
+
+        NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class);
+        if (tunPort != null) {
+            flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
+        }
 
         HashSet<CgPair> visitedPairs = new HashSet<>();
 
-        for (EgKey sepg : ctx.epManager.getGroupsForNode(nodeId)) {
-            // Allow traffic within the same endpoint group if the policy
-            // specifies
-            IndexedTenant tenant = 
-                    ctx.policyResolver.getTenant(sepg.getTenantId());
-            EndpointGroup group = 
-                    tenant.getEndpointGroup(sepg.getEgId());
-            IntraGroupPolicy igp = group.getIntraGroupPolicy();
-            int sepgId = 
-                    ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
-                                                        sepg.getEgId());
-            if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
-                allowSameEpg(t, tiid, flowMap, nodeId, sepgId);
-            }
+        // Used for ARP flows
+        Set<Integer> fdIds = new HashSet<>();
 
-            for (Endpoint src : ctx.epManager.getEPsForNode(nodeId, sepg)) {
-                if (src.getTenant() == null || src.getEndpointGroup() == null)
-                    continue;
-                
-                List<ConditionName> conds = 
-                        ctx.epManager.getCondsForEndpoint(src);
-                ConditionGroup scg = policyInfo.getEgCondGroup(sepg, conds);
-                int scgId = ctx.policyManager.getCondGroupOrdinal(scg);
-                
-                Set<EgKey> peers = policyInfo.getPeers(sepg);
-                for (EgKey depg : peers) {
-                    int depgId = 
-                            ctx.policyManager.getContextOrdinal(depg.getTenantId(), 
-                                                                depg.getEgId());
-                
-                    for (Endpoint dst : ctx.epManager.getEndpointsForGroup(depg)) {
-                
-                        conds = ctx.epManager.getCondsForEndpoint(dst);
-                        ConditionGroup dcg = 
-                                policyInfo.getEgCondGroup(new EgKey(dst.getTenant(), 
-                                                                    dst.getEndpointGroup()),
-                                                          conds);
-                        int dcgId = ctx.policyManager.getCondGroupOrdinal(dcg);
-                        
+        for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
+            for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
+                Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
+                for (EgKey dstEpgKey : peers) {
+                    for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey)) {
+                        // mEPG ordinals
+                        EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
+                                policyInfo, srcEp);
+                        EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
+                                policyInfo, dstEp);
+                        int dcgId = dstEpFwdCxtOrds.getCgId();
+                        int depgId = dstEpFwdCxtOrds.getEpgId();
+                        int scgId = srcEpFwdCxtOrds.getCgId();
+                        int sepgId = srcEpFwdCxtOrds.getEpgId();
+                        NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
+                        fdIds.add(srcEpFwdCxtOrds.getFdId());
+
+                        List<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp);
+                        ConditionGroup scg = policyInfo.getEgCondGroup(srcEpgKey, conds);
+                        conds = ctx.getEndpointManager().getCondsForEndpoint(dstEp);
+                        ConditionGroup dcg = policyInfo.getEgCondGroup(dstEpgKey, conds);
+
+                        Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
+                        List<RuleGroup> rgs = policy.getRules(dcg, scg);
                         CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
-                        if (visitedPairs.contains(p)) continue;
+                        if (visitedPairs.contains(p))
+                            continue;
                         visitedPairs.add(p);
-                        syncPolicy(t, tiid, flowMap, nodeId, policyInfo, 
-                                   p, depg, sepg, dcg, scg);
-                
+                        syncPolicy(flowMap, netElements, rgs, p);
+
+                        // Reverse
+                        policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
+                        rgs = policy.getRules(scg, dcg);
                         p = new CgPair(sepgId, depgId, scgId, dcgId);
-                        if (visitedPairs.contains(p)) continue;
+                        if (visitedPairs.contains(p))
+                            continue;
                         visitedPairs.add(p);
-                        syncPolicy(t, tiid, flowMap, nodeId, policyInfo, 
-                                   p, sepg, depg, scg, dcg);
-                        
+                        syncPolicy(flowMap, netElements, rgs, p);
                     }
                 }
             }
         }
-    }
-    
-    private void allowSameEpg(ReadWriteTransaction t, 
-                              InstanceIdentifier<Table> tiid,
-                              Map<String, FlowCtx> flowMap, NodeId nodeId,
-                              int sepgId) {
-        FlowId flowId = new FlowId(new StringBuilder()
-            .append("intraallow|")
-            .append(sepgId).toString());
-        if (visit(flowMap, flowId.getValue())) {
-            MatchBuilder mb = new MatchBuilder();
-            addNxRegMatch(mb, 
-                          RegMatch.of(NxmNxReg0.class,Long.valueOf(sepgId)),
-                          RegMatch.of(NxmNxReg2.class,Long.valueOf(sepgId)));
-            FlowBuilder flow = base()
-                .setId(flowId)
-                .setMatch(mb.build())
-                .setPriority(65000)
-                .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
-            writeFlow(t, tiid, flow.build());
+
+        // Allow same EPG
+        // Set<Endpoint> visitedEps = new HashSet<>();
+        for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
+            // visitedEps.add(srcEp);
+            for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
+
+                IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
+                EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
+                IntraGroupPolicy igp = group.getIntraGroupPolicy();
+
+                if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
+                    for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
+                        // mEPG ordinals
+                        // if(visitedEps.contains(dstEp)) {
+                        // continue;
+                        // }
+                        // visitedEps.add(dstEp);
+                        EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
+                                policyInfo, srcEp);
+                        EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
+                                policyInfo, dstEp);
+                        int depgId = dstEpFwdCxtOrds.getEpgId();
+                        int sepgId = srcEpFwdCxtOrds.getEpgId();
+                        flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
+                        flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
+                    }
+                }
+            }
+        }
+
+        // Write ARP flows per flood domain.
+        for (Integer fdId : fdIds) {
+            flowMap.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
         }
     }
-    
-    private void allowFromTunnel(ReadWriteTransaction t, 
-                                 InstanceIdentifier<Table> tiid,
-                                 Map<String, FlowCtx> flowMap, NodeId nodeId) {
-        NodeConnectorId tunPort =
-                ctx.switchManager.getTunnelPort(nodeId);
-        if (tunPort == null) return;
+
+    private Flow createArpFlow(Integer fdId) {
+
+        Long etherType = FlowUtils.ARP;
+        // L2 Classifier so 20,000 for now
+        Integer priority = 20000;
+        FlowId flowid = new FlowId(new StringBuilder().append("arp")
+            .append("|")
+            .append(etherType)
+            .append("|")
+            .append(fdId)
+            .toString());
+
+        MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
+
+        addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
+
+        Flow flow = base().setPriority(priority)
+            .setId(flowid)
+            .setMatch(mb.build())
+            .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
+            .build();
+        return flow;
+    }
+
+    private Flow allowSameEpg(int sepgId, int depgId) {
+
+        FlowId flowId = new FlowId(new StringBuilder().append("intraallow|").append(sepgId).toString());
+        MatchBuilder mb = new MatchBuilder();
+        addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
+                RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
+        FlowBuilder flow = base().setId(flowId)
+            .setMatch(mb.build())
+            .setPriority(65000)
+            .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
+        return flow.build();
+    }
+
+    private Flow allowFromTunnel(NodeConnectorId tunPort) {
 
         FlowId flowId = new FlowId("tunnelallow");
-        if (visit(flowMap, flowId.getValue())) {
-            MatchBuilder mb = new MatchBuilder()
-                .setInPort(tunPort);
-            addNxRegMatch(mb, 
-                          RegMatch.of(NxmNxReg1.class,Long.valueOf(0xffffff)));
-            FlowBuilder flow = base()
-                .setId(flowId)
-                .setMatch(mb.build())
-                .setPriority(65000)
-                .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
-            writeFlow(t, tiid, flow.build());
-        }
+        MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
+        addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
+        FlowBuilder flow = base().setId(flowId)
+            .setMatch(mb.build())
+            .setPriority(65000)
+            .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
+        return flow.build();
+
     }
-    
-    private void syncPolicy(ReadWriteTransaction t, 
-                            InstanceIdentifier<Table> tiid,
-                            Map<String, FlowCtx> flowMap, NodeId nodeId,
-                            PolicyInfo policyInfo, 
-                            CgPair p, EgKey sepg, EgKey depg,
-                            ConditionGroup scg, ConditionGroup dcg) 
-                             throws Exception {
-        // XXX - TODO raise an exception for rules between the same
-        // endpoint group that are asymmetric
-        Policy policy = policyInfo.getPolicy(sepg, depg);
-        List<RuleGroup> rgs = policy.getRules(scg, dcg);
-        
+
+    private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> rgs, CgPair p) {
         int priority = 65000;
         for (RuleGroup rg : rgs) {
             TenantId tenantId = rg.getContractTenant().getId();
-            IndexedTenant tenant = ctx.policyResolver.getTenant(tenantId); 
+            IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
             for (Rule r : rg.getRules()) {
-                syncDirection(t, tiid, flowMap, nodeId, tenant,
-                                    p, r, Direction.In, priority);
-                syncDirection(t, tiid, flowMap, nodeId, tenant,
-                                    p, r, Direction.Out, priority);
-                
+                syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority);
+                syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority);
+
                 priority -= 1;
             }
         }
     }
-    
-    private void syncDirection(ReadWriteTransaction t, 
-                               InstanceIdentifier<Table> tiid,
-                               Map<String, FlowCtx> flowMap, NodeId nodeId,
-                               IndexedTenant contractTenant,
-                               CgPair p, Rule r, Direction d, int priority) {
-        for (ClassifierRef cr : r.getClassifierRef()) {
-            if (cr.getDirection() != null && 
-                !cr.getDirection().equals(Direction.Bidirectional) && 
-                !cr.getDirection().equals(d))
+
+    /**
+     * Private internal class for ordering Actions in Rules. The order is
+     * determined first by the value of the order parameter, with the lower
+     * order actions being applied first; for Actions with either the same order
+     * or no order, ordering is lexicographical by name.
+     */
+    private static class ActionRefComparator implements Comparator<ActionRef> {
+
+        public static final ActionRefComparator INSTANCE = new ActionRefComparator();
+
+        @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();
+        }
+
+    }
+
+    private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
+            Direction direction, int priority) {
+        /*
+         * Create the ordered action list. The implicit action is "allow", and
+         * is therefore always in the list
+         *
+         * TODO: revisit implicit vs. default for "allow" TODO: look into
+         * incorporating operational policy for actions
+         */
+
+        // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
+        // referencing in sort
+        List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
+        if (rule.getActionRef() != null) {
+            /*
+             * Pre-sort by references using order, then name
+             */
+            List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
+            Collections.sort(arl, ActionRefComparator.INSTANCE);
+
+            for (ActionRef actionRule : arl) {
+                ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
+                if (actionInstance == null) {
+                    // XXX TODO fail the match and raise an exception
+                    LOG.warn("Action instance {} not found", actionRule.getName().getValue());
+                    return;
+                }
+                Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
+                if (action == null) {
+                    // XXX TODO fail the match and raise an exception
+                    LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
+                    return;
+                }
+
+                Map<String, Object> params = new HashMap<>();
+                if (actionInstance.getParameterValue() != null) {
+                    for (ParameterValue v : actionInstance.getParameterValue()) {
+                        if (v.getName() == null)
+                            continue;
+                        if (v.getIntValue() != null) {
+                            params.put(v.getName().getValue(), v.getIntValue());
+                        } else if (v.getStringValue() != null) {
+                            params.put(v.getName().getValue(), v.getStringValue());
+                        }
+                    }
+                }
+                /*
+                 * Convert the GBP Action to one or more OpenFlow Actions
+                 */
+                actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements);
+            }
+        } else {
+            Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
+            actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
+        }
+
+        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)) {
                 continue;
-            
-            StringBuilder idb = new StringBuilder();
-            // XXX - TODO - implement connection tracking (requires openflow 
-            // extension and data plane support)
-
-            MatchBuilder baseMatch = new MatchBuilder();
-
-            if (d.equals(Direction.In)) {
-                idb.append(p.sepg)
-                    .append("|")
-                    .append(p.scgId)
-                    .append("|")
-                    .append(p.depg)
-                    .append("|")
-                    .append(p.dcgId)
-                    .append("|")
-                    .append(priority);
-                addNxRegMatch(baseMatch, 
-                              RegMatch.of(NxmNxReg0.class,Long.valueOf(p.sepg)),
-                              RegMatch.of(NxmNxReg1.class,Long.valueOf(p.scgId)),
-                              RegMatch.of(NxmNxReg2.class,Long.valueOf(p.depg)),
-                              RegMatch.of(NxmNxReg3.class,Long.valueOf(p.dcgId)));
-            } else {
-                idb.append(p.depg)
-                    .append("|")
-                    .append(p.dcgId)
-                    .append("|")
-                    .append(p.sepg)
-                    .append("|")
-                    .append(p.scgId)
-                    .append("|")
-                    .append(priority);                
-                addNxRegMatch(baseMatch, 
-                              RegMatch.of(NxmNxReg0.class,Long.valueOf(p.depg)),
-                              RegMatch.of(NxmNxReg1.class,Long.valueOf(p.dcgId)),
-                              RegMatch.of(NxmNxReg2.class,Long.valueOf(p.sepg)),
-                              RegMatch.of(NxmNxReg3.class,Long.valueOf(p.scgId)));
             }
 
+            // XXX - TODO - implement connection tracking (requires openflow
+            // extension and data plane support - in 2.4. Will need to handle
+            // case where we are working with mix of nodes.
 
             ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
             if (ci == null) {
                 // XXX TODO fail the match and raise an exception
-                LOG.warn("Classifier instance {} not found", 
-                         cr.getName().getValue());
+                LOG.warn("Classifier instance {} not found", cr.getName().getValue());
                 return;
             }
-            Classifier cfier = SubjectFeatures
-                    .getClassifier(ci.getClassifierDefinitionId());
+            Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
             if (cfier == null) {
                 // XXX TODO fail the match and raise an exception
-                LOG.warn("Classifier definition {} not found", 
-                         ci.getClassifierDefinitionId().getValue());
+                LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
                 return;
             }
-
-            List<MatchBuilder> matches = Collections.singletonList(baseMatch);
-            Map<String,Object> params = new HashMap<>();
+            classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
             for (ParameterValue v : ci.getParameterValue()) {
-                if (v.getName() == null) continue;
+
                 if (v.getIntValue() != null) {
-                    params.put(v.getName().getValue(), v.getIntValue());
+                    paramsFromClassifier.put(v.getName().getValue(), v);
                 } else if (v.getStringValue() != null) {
-                    params.put(v.getName().getValue(), v.getStringValue());
+                    paramsFromClassifier.put(v.getName().getValue(), v);
+                } else if (v.getRangeValue() != null) {
+                    paramsFromClassifier.put(v.getName().getValue(), v);
                 }
             }
-            
-            matches = cfier.updateMatch(matches, params);
-            String baseId = idb.toString();
-            FlowBuilder flow = base()
-                    .setPriority(Integer.valueOf(priority));
-            for (MatchBuilder match : matches) {
-                Match m = match.build();
-                FlowId flowId = new FlowId(baseId + "|" + m.toString());
-                if (visit(flowMap, flowId.getValue())) {
+        }
+        List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
+
+        for (Map<String, ParameterValue> params : derivedParamsByName) {
+            for (ClassifierDefinitionId clDefId : classifiers) {
+                Classifier classifier = SubjectFeatures.getClassifier(clDefId);
+                StringBuilder idb = new StringBuilder();
+                // XXX - TODO - implement connection tracking (requires openflow
+                // extension and data plane support - in 2.4. Will need to handle
+                // case where we are working with mix of nodes.
+
+                MatchBuilder baseMatch = new MatchBuilder();
+                if (direction.equals(Direction.In)) {
+                    idb.append(cgPair.sepg)
+                        .append("|")
+                        .append(cgPair.scgId)
+                        .append("|")
+                        .append(cgPair.depg)
+                        .append("|")
+                        .append(cgPair.dcgId)
+                        .append("|")
+                        .append(priority);
+                    addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
+                            RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
+                            RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
+                            RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
+                } else {
+                    idb.append(cgPair.depg)
+                        .append("|")
+                        .append(cgPair.dcgId)
+                        .append("|")
+                        .append(cgPair.sepg)
+                        .append("|")
+                        .append(cgPair.scgId)
+                        .append("|")
+                        .append(priority);
+                    addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
+                            RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
+                            RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
+                            RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
+                }
+
+                List<MatchBuilder> matches = new ArrayList<>();
+                matches.add(baseMatch);
+
+                ClassificationResult result = classifier.updateMatch(matches, params);
+                if (!result.isSuccessfull()) {
+                    // TODO consider different handling.
+                    throw new IllegalArgumentException(result.getErrorMessage());
+                }
+                String baseId = idb.toString();
+                FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
+                for (MatchBuilder match : result.getMatchBuilders()) {
+                    Match m = match.build();
+                    FlowId flowId = new FlowId(baseId + "|" + m.toString());
                     flow.setMatch(m)
                         .setId(flowId)
                         .setPriority(Integer.valueOf(priority))
-                        .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
-                    writeFlow(t, tiid, flow.build());
+                        .setInstructions(instructions(applyActionIns(actionBuilderList)));
+                    flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build());
                 }
             }
-        } 
-
+        }
     }
 
     @Immutable
     private static class CgPair {
+
         private final int sepg;
         private final int depg;
         private final int scgId;
         private final int dcgId;
-        
+
         public CgPair(int sepg, int depg, int scgId, int dcgId) {
             super();
             this.sepg = sepg;
@@ -355,4 +475,49 @@ public class PolicyEnforcer extends FlowTable {
             return true;
         }
     }
+
+    public class NetworkElements {
+        Endpoint src;
+        Endpoint dst;
+        NodeId nodeId;
+        EndpointFwdCtxOrdinals srcOrds;
+        EndpointFwdCtxOrdinals dstOrds;
+
+        public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception {
+            this.src=src;
+            this.dst=dst;
+            this.nodeId = nodeId;
+            this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src);
+            this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst);
+        }
+
+
+
+        public EndpointFwdCtxOrdinals getSrcOrds() {
+            return srcOrds;
+        }
+
+
+
+        public EndpointFwdCtxOrdinals getDstOrds() {
+            return dstOrds;
+        }
+
+
+        public Endpoint getSrc() {
+            return src;
+        }
+
+
+        public Endpoint getDst() {
+            return dst;
+        }
+
+
+        public NodeId getNodeId() {
+            return nodeId;
+        }
+
+
+    }
 }