a121d2da4c57d7faf3c11061d8c65dffd26e450a
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / PolicyEnforcer.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
10
11 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.writeActionIns;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.EndpointManager.isExternal;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import javax.annotation.concurrent.Immutable;
30
31 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
32 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
33 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
34 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
35 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
38 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
39 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
40 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
41 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
42 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
43 import org.opendaylight.groupbasedpolicy.resolver.EndpointConstraint;
44 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
45 import org.opendaylight.groupbasedpolicy.resolver.Policy;
46 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
47 import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
86
87 import com.google.common.collect.ComparisonChain;
88 import com.google.common.collect.Ordering;
89 import com.google.common.collect.Table.Cell;
90
91 /**
92  * Manage the table that enforces policy on the traffic. Traffic is denied
93  * unless specifically allowed by policy
94  */
95 public class PolicyEnforcer extends FlowTable {
96
97     protected static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
98
99     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoEgressNatInstruction;
100     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoExternalInstruction;
101
102     public static short TABLE_ID;
103
104     public PolicyEnforcer(OfContext ctx, short tableId) {
105         super(ctx);
106         this.TABLE_ID=tableId;
107         this.gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
108         this.gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
109     }
110
111
112
113
114
115     @Override
116     public short getTableId() {
117         return TABLE_ID;
118     }
119
120     @Override
121     public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
122
123         flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
124
125         NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class);
126         if (tunPort != null) {
127             flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
128         }
129
130         HashSet<CgPair> visitedPairs = new HashSet<>();
131
132         // Used for ARP flows
133         Set<Integer> fdIds = new HashSet<>();
134
135         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
136             for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
137                 Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
138                 for (EgKey dstEpgKey : peers) {
139                     Set<Endpoint> dstEndpoints = new HashSet<>();
140                     dstEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey));
141                     dstEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(dstEpgKey));
142                     for (Endpoint dstEp : dstEndpoints) {
143                         // mEPG ordinals
144                         EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
145                                 policyInfo, srcEp);
146                         EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
147                                 policyInfo, dstEp);
148                         int dcgId = dstEpFwdCxtOrds.getCgId();
149                         int depgId = dstEpFwdCxtOrds.getEpgId();
150                         int scgId = srcEpFwdCxtOrds.getCgId();
151                         int sepgId = srcEpFwdCxtOrds.getEpgId();
152                         NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
153                         fdIds.add(srcEpFwdCxtOrds.getFdId());
154
155                         Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
156                         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints: getActiveRulesBetweenEps(policy, dstEp, srcEp)) {
157                             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
158                                 .getL3EpPrefixes());
159                             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
160                                 .getL3EpPrefixes());
161                             CgPair p = new CgPair(depgId, sepgId, dcgId, scgId, dIpPrefixes, sIpPrefixes);
162                             if (visitedPairs.contains(p))
163                                 continue;
164                             visitedPairs.add(p);
165                             syncPolicy(flowMap, netElements, activeRulesByConstraints.getValue(), p);
166                         }
167
168                         // Reverse
169                         policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
170                         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(policy, srcEp, dstEp)) {
171                             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
172                                 .getL3EpPrefixes());
173                             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
174                                 .getL3EpPrefixes());
175                             CgPair p = new CgPair(sepgId, depgId, scgId, dcgId, sIpPrefixes, dIpPrefixes);
176                             if (visitedPairs.contains(p))
177                                 continue;
178                             visitedPairs.add(p);
179                             syncPolicy(flowMap, netElements, activeRulesByConstraints.getValue(), p);
180                         }
181                     }
182                 }
183             }
184         }
185
186         // Allow same EPG
187         // Set<Endpoint> visitedEps = new HashSet<>();
188         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
189             // visitedEps.add(srcEp);
190             for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
191
192                 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
193                 EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
194                 IntraGroupPolicy igp = group.getIntraGroupPolicy();
195
196                 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
197                     for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
198                         // mEPG ordinals
199                         // if(visitedEps.contains(dstEp)) {
200                         // continue;
201                         // }
202                         // visitedEps.add(dstEp);
203                         EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
204                                 policyInfo, srcEp);
205                         EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
206                                 policyInfo, dstEp);
207                         int depgId = dstEpFwdCxtOrds.getEpgId();
208                         int sepgId = srcEpFwdCxtOrds.getEpgId();
209                         flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
210                         flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
211                     }
212                 }
213             }
214         }
215
216         // Write ARP flows per flood domain.
217         for (Integer fdId : fdIds) {
218             flowMap.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
219         }
220     }
221
222     private Flow createArpFlow(Integer fdId) {
223
224         Long etherType = FlowUtils.ARP;
225         // L2 Classifier so 20,000 for now
226         Integer priority = 20000;
227         FlowId flowid = new FlowId(new StringBuilder().append("arp")
228             .append("|")
229             .append(etherType)
230             .append("|")
231             .append(fdId)
232             .toString());
233
234         MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
235
236         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
237
238         Flow flow = base().setPriority(priority)
239             .setId(flowid)
240             .setMatch(mb.build())
241             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
242             .build();
243         return flow;
244     }
245
246     private Flow allowSameEpg(int sepgId, int depgId) {
247
248         FlowId flowId = new FlowId(new StringBuilder().append("intraallow|").append(sepgId).toString());
249         MatchBuilder mb = new MatchBuilder();
250         addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
251                 RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
252         FlowBuilder flow = base().setId(flowId)
253             .setMatch(mb.build())
254             .setPriority(65000)
255             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
256         return flow.build();
257     }
258
259     private Flow allowFromTunnel(NodeConnectorId tunPort) {
260
261         FlowId flowId = new FlowId("tunnelallow");
262         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
263         addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
264         FlowBuilder flow = base().setId(flowId)
265             .setMatch(mb.build())
266             .setPriority(65000)
267             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
268         return flow.build();
269
270     }
271
272     private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> rgs, CgPair p) {
273         int priority = 65000;
274         for (RuleGroup rg : rgs) {
275             TenantId tenantId = rg.getContractTenant().getId();
276             IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
277             for (Rule r : rg.getRules()) {
278                 syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority);
279                 syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority);
280
281                 priority -= 1;
282             }
283         }
284     }
285
286     /**
287      * Private internal class for ordering Actions in Rules. The order is
288      * determined first by the value of the order parameter, with the lower
289      * order actions being applied first; for Actions with either the same order
290      * or no order, ordering is lexicographical by name.
291      */
292     private static class ActionRefComparator implements Comparator<ActionRef> {
293
294         public static final ActionRefComparator INSTANCE = new ActionRefComparator();
295
296         @Override
297         public int compare(ActionRef arg0, ActionRef arg1) {
298             return ComparisonChain.start()
299                 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
300                 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
301                 .result();
302         }
303
304     }
305
306     private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
307             Direction direction, int priority) {
308         /*
309          * Create the ordered action list. The implicit action is "allow", and
310          * is therefore always in the list
311          *
312          * TODO: revisit implicit vs. default for "allow" TODO: look into
313          * incorporating operational policy for actions
314          */
315
316         // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
317         // referencing in sort
318         List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
319         if (rule.getActionRef() != null) {
320             /*
321              * Pre-sort by references using order, then name
322              */
323             List<ActionRef> actionRefList = new ArrayList<ActionRef>(rule.getActionRef());
324             Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
325
326             for (ActionRef actionRule : actionRefList) {
327                 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
328                 if (actionInstance == null) {
329                     // XXX TODO fail the match and raise an exception
330                     LOG.warn("Action instance {} not found", actionRule.getName().getValue());
331                     return;
332                 }
333                 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
334                 if (action == null) {
335                     // XXX TODO fail the match and raise an exception
336                     LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
337                     return;
338                 }
339
340                 Map<String, Object> params = new HashMap<>();
341                 if (actionInstance.getParameterValue() != null) {
342                     for (ParameterValue v : actionInstance.getParameterValue()) {
343                         if (v.getName() == null)
344                             continue;
345                         if (v.getIntValue() != null) {
346                             params.put(v.getName().getValue(), v.getIntValue());
347                         } else if (v.getStringValue() != null) {
348                             params.put(v.getName().getValue(), v.getStringValue());
349                         }
350                     }
351                 }
352                 /*
353                  * Convert the GBP Action to one or more OpenFlow Actions
354                  */
355                 actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements);
356             }
357         } else {
358             Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
359             actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
360         }
361
362         Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
363         Set<ClassifierDefinitionId> classifiers = new HashSet<>();
364         for (ClassifierRef cr : rule.getClassifierRef()) {
365             if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
366                     && !cr.getDirection().equals(direction)) {
367                 continue;
368             }
369
370             // XXX - TODO - implement connection tracking (requires openflow
371             // extension and data plane support - in 2.4. Will need to handle
372             // case where we are working with mix of nodes.
373
374             ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
375             if (ci == null) {
376                 // XXX TODO fail the match and raise an exception
377                 LOG.warn("Classifier instance {} not found", cr.getName().getValue());
378                 return;
379             }
380             Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
381             if (cfier == null) {
382                 // XXX TODO fail the match and raise an exception
383                 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
384                 return;
385             }
386             classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
387             for (ParameterValue v : ci.getParameterValue()) {
388                 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
389                     if (v.getIntValue() != null
390                             || v.getStringValue() != null
391                             || v.getRangeValue() != null) {
392                         paramsFromClassifier.put(v.getName().getValue(), v);
393                     }
394                 } else {
395                     if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
396                         throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
397                                 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
398                     }
399                 }
400             }
401         }
402         if(classifiers.isEmpty()) {
403             return;
404         }
405         List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
406         String baseId = createBaseFlowId(direction, cgPair, priority);
407         List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
408         for (Map<String, ParameterValue> params : derivedParamsByName) {
409             List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
410             if (cgPair.sIpPrefixes.isEmpty() && cgPair.dIpPrefixes.isEmpty()) {
411                 matchBuildersToResolve.add(createBaseMatch(direction, cgPair, null, null));
412             } else if (!cgPair.sIpPrefixes.isEmpty() && cgPair.dIpPrefixes.isEmpty()) {
413                 for (IpPrefix sIpPrefix : cgPair.sIpPrefixes) {
414                     matchBuildersToResolve.add(createBaseMatch(direction, cgPair, sIpPrefix, null));
415                 }
416             } else if (cgPair.sIpPrefixes.isEmpty() && !cgPair.dIpPrefixes.isEmpty()) {
417                 for (IpPrefix dIpPrefix : cgPair.sIpPrefixes) {
418                     matchBuildersToResolve.add(createBaseMatch(direction, cgPair, null, dIpPrefix));
419                 }
420             } else {
421                 for (IpPrefix sIpPrefix : cgPair.sIpPrefixes) {
422                     for (IpPrefix dIpPrefix : cgPair.sIpPrefixes) {
423                         matchBuildersToResolve.add(createBaseMatch(direction, cgPair, sIpPrefix, dIpPrefix));
424                     }
425                 }
426             }
427             for (ClassifierDefinitionId clDefId : classifiers) {
428                 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
429                 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
430                 if (!result.isSuccessfull()) {
431                     // TODO consider different handling.
432                     throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName() + ".\nCause: "
433                             + result.getErrorMessage());
434                 }
435                 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
436             }
437             flowMatchBuilders.addAll(matchBuildersToResolve);
438         }
439
440
441
442         FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
443         for (MatchBuilder match : flowMatchBuilders) {
444             Match m = match.build();
445             FlowId flowId = new FlowId(baseId + "|" + m.toString());
446             flow.setMatch(m)
447                 .setId(flowId)
448                 .setPriority(Integer.valueOf(priority));
449                         // If destination is External, the last Action ALLOW must be changed to goto NAT/External table.
450         if (isExternal(netElements.getDst())) {
451             flow.setInstructions(instructions(getGotoEgressNatInstruction()));
452         } else {
453             flow.setInstructions(instructions(applyActionIns(actionBuilderList)));
454         }
455             flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build());
456         }
457     }
458
459     private String createBaseFlowId(Direction direction, CgPair cgPair, int priority) {
460         StringBuilder idb = new StringBuilder();
461         if (direction.equals(Direction.In)) {
462             idb.append(cgPair.sepg)
463                     .append("|")
464                     .append(cgPair.scgId)
465                     .append("|")
466                     .append(cgPair.depg)
467                     .append("|")
468                     .append(cgPair.dcgId)
469                     .append("|")
470                     .append(priority);
471         } else {
472             idb.append(cgPair.depg)
473                     .append("|")
474                     .append(cgPair.dcgId)
475                     .append("|")
476                     .append(cgPair.sepg)
477                     .append("|")
478                     .append(cgPair.scgId)
479                     .append("|")
480                     .append(priority);
481         }
482         return idb.toString();
483     }
484
485     private MatchBuilder createBaseMatch(Direction direction, CgPair cgPair, IpPrefix sIpPrefix, IpPrefix dIpPrefix) {
486         MatchBuilder baseMatch = new MatchBuilder();
487         if (direction.equals(Direction.In)) {
488             addNxRegMatch(baseMatch,
489                     RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
490                     RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
491                     RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
492                     RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
493             if (sIpPrefix != null) {
494                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
495             }
496             if (dIpPrefix != null) {
497                 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
498             }
499         } else {
500             addNxRegMatch(baseMatch,
501                     RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
502                     RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
503                     RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
504                     RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
505             if (sIpPrefix != null) {
506                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
507             }
508             if (dIpPrefix != null) {
509                 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
510             }
511         }
512         return baseMatch;
513     }
514
515     private Layer3Match createLayer3Match(IpPrefix ipPrefix, boolean isSrc) {
516         if (ipPrefix.getIpv4Prefix() != null) {
517             if (isSrc) {
518                 return new Ipv4MatchBuilder().setIpv4Source(ipPrefix.getIpv4Prefix()).build();
519             } else {
520                 return new Ipv4MatchBuilder().setIpv4Destination(ipPrefix.getIpv4Prefix()).build();
521             }
522         } else {
523             if (isSrc) {
524                 return new Ipv6MatchBuilder().setIpv6Source(ipPrefix.getIpv6Prefix()).build();
525             } else {
526                 return new Ipv6MatchBuilder().setIpv6Destination(ipPrefix.getIpv6Prefix()).build();
527             }
528         }
529     }
530
531     // TODO: move to a common utils for all renderers
532     public List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>>
533                 getActiveRulesBetweenEps(Policy policy, Endpoint consEp, Endpoint provEp) {
534         List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
535         if (policy.getRuleMap() != null) {
536             for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
537                 EndpointConstraint consEpConstraint = cell.getRowKey();
538                 EndpointConstraint provEpConstraint = cell.getColumnKey();
539                 if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
540                     rulesWithEpConstraints.add(cell);
541                 }
542             }
543         }
544         return rulesWithEpConstraints;
545     }
546
547     private boolean epMatchesConstraint(Endpoint ep, EndpointConstraint constraint) {
548         List<ConditionName> epConditions = Collections.emptyList();
549         if (ep.getCondition() != null) {
550             epConditions = ep.getCondition();
551         }
552         return constraint.getConditionSet().matches(epConditions);
553     }
554
555     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
556         return gotoEgressNatInstruction;
557     }
558
559     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
560         return gotoExternalInstruction;
561     }
562
563     @Immutable
564     private static class CgPair {
565
566         private final int sepg;
567         private final int depg;
568         private final int scgId;
569         private final int dcgId;
570         private final Set<IpPrefix> sIpPrefixes;
571         private final Set<IpPrefix> dIpPrefixes;
572
573         public CgPair(int sepg, int depg, int scgId, int dcgId, Set<IpPrefix> sIpPrefixes, Set<IpPrefix> dIpPrefixes) {
574             super();
575             this.sepg = sepg;
576             this.depg = depg;
577             this.scgId = scgId;
578             this.dcgId = dcgId;
579             this.sIpPrefixes = sIpPrefixes;
580             this.dIpPrefixes = dIpPrefixes;
581         }
582
583         @Override
584         public int hashCode() {
585             final int prime = 31;
586             int result = 1;
587             result = prime * result + ((dIpPrefixes == null) ? 0 : dIpPrefixes.hashCode());
588             result = prime * result + dcgId;
589             result = prime * result + depg;
590             result = prime * result + ((sIpPrefixes == null) ? 0 : sIpPrefixes.hashCode());
591             result = prime * result + scgId;
592             result = prime * result + sepg;
593             return result;
594         }
595
596         @Override
597         public boolean equals(Object obj) {
598             if (this == obj)
599                 return true;
600             if (obj == null)
601                 return false;
602             if (getClass() != obj.getClass())
603                 return false;
604             CgPair other = (CgPair) obj;
605             if (dIpPrefixes == null) {
606                 if (other.dIpPrefixes != null)
607                     return false;
608             } else if (!dIpPrefixes.equals(other.dIpPrefixes))
609                 return false;
610             if (dcgId != other.dcgId)
611                 return false;
612             if (sIpPrefixes == null) {
613                 if (other.sIpPrefixes != null)
614                     return false;
615             } else if (!sIpPrefixes.equals(other.sIpPrefixes))
616                 return false;
617             if (depg != other.depg)
618                 return false;
619             if (scgId != other.scgId)
620                 return false;
621             if (sepg != other.sepg)
622                 return false;
623             return true;
624         }
625     }
626
627     public class NetworkElements {
628         Endpoint src;
629         Endpoint dst;
630         NodeId nodeId;
631         EndpointFwdCtxOrdinals srcOrds;
632         EndpointFwdCtxOrdinals dstOrds;
633
634         public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception {
635             this.src=src;
636             this.dst=dst;
637             this.nodeId = nodeId;
638             this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src);
639             this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst);
640         }
641
642
643
644         public EndpointFwdCtxOrdinals getSrcOrds() {
645             return srcOrds;
646         }
647
648
649
650         public EndpointFwdCtxOrdinals getDstOrds() {
651             return dstOrds;
652         }
653
654
655         public Endpoint getSrc() {
656             return src;
657         }
658
659
660         public Endpoint getDst() {
661             return dst;
662         }
663
664
665         public NodeId getNodeId() {
666             return nodeId;
667         }
668
669
670     }
671 }