Fixed NAT in OFOverlay based on EIG
[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.applyActionIns;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
16
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import javax.annotation.concurrent.Immutable;
27
28 import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
29 import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
30 import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
31 import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
32 import org.opendaylight.groupbasedpolicy.dto.EgKey;
33 import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint;
34 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
35 import org.opendaylight.groupbasedpolicy.dto.Policy;
36 import org.opendaylight.groupbasedpolicy.dto.RuleGroup;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
38 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
39 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
40 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
41 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
42 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
43 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
44 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
45 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
46 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
47 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
48 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
49 import org.opendaylight.groupbasedpolicy.util.TenantUtils;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
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.OfOverlayContext;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup.IntraGroupPolicy;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.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.ArrayListMultimap;
88 import com.google.common.collect.ComparisonChain;
89 import com.google.common.collect.ListMultimap;
90 import com.google.common.collect.Ordering;
91 import com.google.common.collect.Table.Cell;
92
93 /**
94  * Manage the table that enforces policy on the traffic. Traffic is denied
95  * unless specifically allowed by policy
96  */
97 public class PolicyEnforcer extends FlowTable {
98
99     private static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
100     public static short TABLE_ID;
101     private static boolean isReversedPolicy;
102     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoEgressNatInstruction;
103     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoExternalInstruction;
104     private HashSet<PolicyPair> visitedPairs = new HashSet<>();
105     private HashSet<PolicyPair> visitedReversePairs = new HashSet<>();
106     private List<Rule> reversedActiveRules = new ArrayList<>();
107     private ListMultimap<EgKey, EgKey> resolvedEpgPairs = ArrayListMultimap.create();
108     private boolean directPathFlowsCreated = false;
109     private boolean reversePathFlowsCreated = false;
110
111     public PolicyEnforcer(OfContext ctx, short tableId) {
112         super(ctx);
113         TABLE_ID = tableId;
114         isReversedPolicy = false;
115         gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
116         gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER());
117     }
118
119     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
120         return gotoEgressNatInstruction;
121     }
122
123     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
124         return gotoExternalInstruction;
125     }
126
127     @Override
128     public short getTableId() {
129         return TABLE_ID;
130     }
131
132     @Override
133     public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
134
135         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
136
137         NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
138         if (tunPort != null) {
139             ofWriter.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
140         }
141
142         visitedPairs = new HashSet<>();
143         reversedActiveRules = new ArrayList<>();
144         visitedReversePairs = new HashSet<>();
145         resolvedEpgPairs = ArrayListMultimap.create();
146
147         // Used for ARP flows
148         Set<Integer> fdIds = new HashSet<>();
149
150         for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
151             for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
152                 Set<EgKey> peers = ctx.getCurrentPolicy().getPeers(sourceEpgKey);
153                 for (EgKey destinationEpgKey : peers) {
154
155                     Set<Endpoint> destinationEndpoints = new HashSet<>();
156                     destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(destinationEpgKey));
157                     destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(destinationEpgKey));
158                     for (Endpoint destinationEp : destinationEndpoints) {
159
160                         EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
161                         if (srcEpFwdCxtOrdinals == null) {
162                             LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", sourceEp);
163                             continue;
164                         }
165
166                         EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEp);
167                         if (dstEpFwdCxtOrdinals == null) {
168                             LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEp);
169                             continue;
170                         }
171
172                         fdIds.add(srcEpFwdCxtOrdinals.getFdId());
173                         NetworkElements netElements = new NetworkElements(sourceEp, destinationEp, sourceEpgKey,
174                                 destinationEpgKey, nodeId, ctx);
175
176                         // Get policy in both directions
177                         Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destinationEpgKey, sourceEpgKey);
178                         Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpgKey, destinationEpgKey);
179                         reversedActiveRules = getRules(getActiveRulesBetweenEps(destinationEpgPolicy, sourceEp, destinationEp));
180
181                         // Resolve flows in both directions if possible according to policy. Get back status of resolution
182                         PathStatus status = resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy);
183
184                         // When source Epg policy creates no flows, destination Epg policy has to be resolved
185                         if (status.equals(PathStatus.none)) {
186                             resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, false);
187                         }
188                         // When source Epg policy creates flows only in one direction, the other direction has to be
189                         // created here. Is essential to revert directions to prevent flow overriding and incorrect nsp
190                         // evaluation
191                         else if (status.equals(PathStatus.partial)) {
192                             resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, true);
193                         }
194                     }
195                 }
196             }
197         }
198
199         // Allow same EPG
200         allowSameEpg(nodeId, ofWriter);
201
202         // Write ARP flows per flood domain
203         for (Integer fdId : fdIds) {
204             ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
205         }
206     }
207
208     private PathStatus resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy) {
209         isReversedPolicy = false;
210         directPathFlowsCreated = false;
211         reversePathFlowsCreated = false;
212
213         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
214                 directPolicy, netElements.getDstEp(), netElements.getSrcEp())) {
215             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
216                     .getL3EpPrefixes());
217             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
218                     .getL3EpPrefixes());
219             PolicyPair policyPair = new PolicyPair(netElements.getDstEpOrdinals().getEpgId(), netElements.getSrcEpOrdinals().getEpgId(),
220                     netElements.getDstEpOrdinals().getCgId(), netElements.getSrcEpOrdinals().getCgId(), dIpPrefixes, sIpPrefixes,
221                     netElements.getDstNodeId(), netElements.getSrcNodeId());
222             if (visitedPairs.contains(policyPair)) {
223                 LOG.trace("PolicyEnforcer: Already visited PolicyPair {}, endpoints {} {} skipped",
224                         policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
225                 continue;
226             } else {
227                 LOG.trace("PolicyEnforcer: Visiting PolicyPair {} endpoints {} {}", policyPair,
228                         netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
229                 visitedPairs.add(policyPair);
230             }
231
232             int priority = 65000;
233             for (RuleGroup rg : activeRulesByConstraints.getValue()) {
234                 TenantId tenantId = rg.getContractTenant().getId();
235                 IndexedTenant tenant = ctx.getTenant(tenantId);
236                 for (Rule rule : rg.getRules()) {
237
238                     // Find all rules in the same traffic direction
239                     List<Rule> sameDirectionRules = findRulesInSameDirection(rule, reversedActiveRules);
240                     if (sameDirectionRules.isEmpty()) {
241                         sameDirectionRules.add(rule);
242                     }
243                     sameDirectionRules = Ordering.from(TenantUtils.RULE_COMPARATOR)
244                             .immutableSortedCopy(sameDirectionRules);
245
246                     // Create flows for every pair of rules
247                     for (Rule oppositeRule : sameDirectionRules) {
248
249                         // Evaluate which rule has more specific matches
250                         Rule ruleWithMatches = findRuleWithSpecificMatches(rule, oppositeRule, tenant);
251                         Rule ruleWithActions = mergeRuleActions(rule, oppositeRule, tenant);
252                         if (ruleWithMatches == null) {
253                             LOG.trace("No matches found for pair of rules {}, {}", rule, oppositeRule);
254                             continue;
255                         }
256                         if (ruleWithActions == null) {
257                             LOG.trace("No actions found for pair of rules {}, {}", rule, oppositeRule);
258                             continue;
259                         }
260
261                         // Preserve original rule direction
262                         Set<Direction> directions = getRuleDirections(rule);
263
264                         for(Direction direction : directions) {
265
266                             // Create list of matches/actions. Also creates chain flows when specific action requires it
267                             List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant,
268                                     ruleWithMatches);
269                             List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant,
270                                     ruleWithMatches);
271
272                             List<ActionBuilder> actions = createActions(ofWriter, netElements, direction,
273                                     policyPair, tenant, ruleWithActions, false);
274
275                             // Compose flows
276                             createFlows(inMatches, actions, netElements, ofWriter, priority);
277                             createFlows(outMatches, actions, netElements, ofWriter, priority);
278
279                             priority -= 1;
280
281                             // Keep info about what direction has flows already created
282                             if (direction.equals(Direction.In)) {
283                                 directPathFlowsCreated = true;
284                             }
285                             if (direction.equals(Direction.Out)) {
286                                 reversePathFlowsCreated = true;
287                             }
288
289                             // Fully resolved Ep groups are saved to prevent duplicates
290                             if (directPathFlowsCreated && reversePathFlowsCreated) {
291                                 LOG.trace("Epg pair added: {}, {} ", netElements.getSrcEpg(), netElements.getDstEpg());
292                                 resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
293                             }
294                         }
295                     }
296                 }
297             }
298
299         }
300         // Returns appropriate result of resolving
301         if (directPathFlowsCreated && reversePathFlowsCreated) {
302             return PathStatus.both;
303         } else if ((!directPathFlowsCreated && reversePathFlowsCreated) || (directPathFlowsCreated && !reversePathFlowsCreated)) {
304             return PathStatus.partial;
305         } else {
306             return PathStatus.none;
307         }
308     }
309
310     private Set<Direction> getRuleDirections(Rule ruleWithMatches) {
311         Set<Direction> directions = new HashSet<>();
312         for (ClassifierRef classifierRef : ruleWithMatches.getClassifierRef()) {
313             if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.In) {
314                 directions.add(classifierRef.getDirection());
315             }
316             if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.Out) {
317                 directions.add(classifierRef.getDirection());
318             }
319         }
320         if (directions.isEmpty()) {
321             directions.add(Direction.Bidirectional);
322         }
323         return directions;
324     }
325
326     private Rule mergeRuleActions(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
327         if (oppositeRule.equals(rule)) {
328             return rule;
329         }
330
331         Action ruleAction = null;
332         Action oppositeRuleAction = null;
333
334         // For now, only allow action and chain action is supported
335         for (ActionRef actionRef : rule.getActionRef()) {
336             ActionInstance actionInstance = tenant.getAction(actionRef.getName());
337             if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
338                 ruleAction = new AllowAction();
339             }
340             if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
341                 ruleAction = new ChainAction();
342             }
343         }
344         for (ActionRef actionRef : oppositeRule.getActionRef()) {
345             ActionInstance actionInstance = tenant.getAction(actionRef.getName());
346             if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
347                 oppositeRuleAction = new AllowAction();
348             }
349             if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
350                 oppositeRuleAction = new ChainAction();
351             }
352         }
353
354         if (ruleAction == null && oppositeRuleAction == null) {
355             return null;
356         } else if (ruleAction != null && ruleAction.getClass().equals(AllowAction.class)) {
357             return oppositeRule;
358         } else if (oppositeRuleAction != null && oppositeRuleAction.getClass().equals(AllowAction.class)) {
359             return rule;
360         } else {
361             // TODO both rules have chain action - add support for more different chain actions. This works for now
362             return rule;
363         }
364     }
365
366     private Rule findRuleWithSpecificMatches(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
367         if (oppositeRule.equals(rule)) {
368             return rule;
369         }
370
371         // TODO check all classifierRefs
372         ClassifierRef ruleClassifierRef = rule.getClassifierRef().get(0);
373         ClassifierRef oppositeRuleClassifierRef = oppositeRule.getClassifierRef().get(0);
374
375         ClassifierInstance ruleClassifierInstance = tenant.getClassifier(ruleClassifierRef.getInstanceName());
376         ClassifierInstance oppositeRuleClassifierInstance = tenant.getClassifier(oppositeRuleClassifierRef.getInstanceName());
377
378         if (ruleClassifierInstance == null) {
379             LOG.trace("Classifier instance not found, ClassifierRef name: {} ", ruleClassifierRef.getInstanceName());
380             return null;
381         }
382         if (oppositeRuleClassifierInstance == null) {
383             LOG.trace("Opposite classifier instance not found, ClassifierRef name: {} ", oppositeRuleClassifierRef.getInstanceName());
384             return null;
385         }
386
387         // Check ethertype. Values must be equal
388         for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
389             for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
390                 if ((ruleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
391                         && oppositeRuleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)) {
392                     if (!ruleParameter.getIntValue().equals(oppositeRuleParameter.getIntValue())) {
393                         LOG.trace("Ethertype values are not equal, rule: {}, opposite rule: {} ", rule, oppositeRule);
394                         return null;
395                     }
396                 }
397             }
398         }
399         // Check proto if exists. Values must be equal or missing
400         ParameterValue ruleProtoParameter = null;
401         ParameterValue oppositeRuleProtoParameter = null;
402         for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
403             if (ruleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
404                 ruleProtoParameter = ruleParameter;
405             }
406         }
407         for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
408             if (oppositeRuleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
409                 oppositeRuleProtoParameter = oppositeRuleParameter;
410             }
411         }
412
413         if (ruleProtoParameter == null || ruleProtoParameter.getIntValue() == null) {
414             return oppositeRule;
415         } else if (oppositeRuleProtoParameter == null || oppositeRuleProtoParameter.getIntValue() == null) {
416             return rule;
417         } else if (!ruleProtoParameter.getIntValue().equals(oppositeRuleProtoParameter.getIntValue())) {
418             LOG.trace("Proto parameters are not equal, rule parameters: {}, opposite rule parameters {} ",
419                     ruleProtoParameter, oppositeRuleProtoParameter);
420             return null;
421         }
422
423         // Check ports
424         // TODO add support for port ranges
425         ParameterValue ruleL4Src = null;
426         ParameterValue oppositeRuleL4Src = null;
427         ParameterValue ruleL4Dst = null;
428         ParameterValue oppositeRuleL4Dst = null;
429
430         for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
431             if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
432                 ruleL4Src = ruleParameter;
433             }
434             if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
435                 ruleL4Dst = ruleParameter;
436             }
437         }
438         for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
439             if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
440                 oppositeRuleL4Src = oppositeRuleParameter;
441             }
442             if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
443                 oppositeRuleL4Dst = oppositeRuleParameter;
444             }
445         }
446
447         if (ruleL4Src == null && ruleL4Dst == null && oppositeRuleL4Src == null && oppositeRuleL4Dst == null) {
448             return rule;
449         }
450
451         // Source rules
452         if (ruleL4Src == null && oppositeRuleL4Src != null) {
453             return oppositeRule;
454         }
455         if (ruleL4Src != null && oppositeRuleL4Src == null) {
456             return rule;
457         }
458         if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
459                 && ruleL4Src.equals(oppositeRuleL4Src)) {
460             return rule;
461         }
462         if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
463                 && !ruleL4Src.equals(oppositeRuleL4Src)) {
464             return null;
465         }
466
467         // Destination rules
468         if (ruleL4Dst == null && oppositeRuleL4Dst != null) {
469             return oppositeRule;
470         }
471         if (ruleL4Dst != null && oppositeRuleL4Dst == null) {
472             return rule;
473         }
474         if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
475                 && ruleL4Dst.equals(oppositeRuleL4Dst)) {
476             return rule;
477         }
478         if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
479                 && !ruleL4Dst.equals(oppositeRuleL4Dst)) {
480             return null;
481         }
482
483         return null;
484     }
485
486     private void resolveDestinationEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy reversedPolicy,
487                                              boolean isReverted) {
488         isReversedPolicy = true;
489         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
490                 reversedPolicy, netElements.getSrcEp(), netElements.getDstEp())) {
491             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
492                     .getL3EpPrefixes());
493             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
494                     .getL3EpPrefixes());
495             PolicyPair policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getEpgId(),
496                     netElements.getSrcEpOrdinals().getCgId(), netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
497                     netElements.getSrcNodeId(), netElements.getDstNodeId());
498             if (visitedReversePairs.contains(policyPair)) {
499                 LOG.trace(
500                         "PolicyEnforcer: Reverse: Already visited PolicyPair {}, endpoints {} {} skipped",
501                         policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
502                 continue;
503             } else {
504                 LOG.trace("PolicyEnforcer: Reverse: Visiting: PolicyPair {} via endpoints {} {}",
505                         policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
506                 visitedReversePairs.add(policyPair);
507
508             }
509             int priority = 65000;
510             for (RuleGroup rg : activeRulesByConstraints.getValue()) {
511                 TenantId tenantId = rg.getContractTenant().getId();
512                 IndexedTenant tenant = ctx.getTenant(tenantId);
513                 for (Rule rule : rg.getRules()) {
514
515                     Set<Direction> directions = getRuleDirections(rule);
516                     if (directions.isEmpty()) {
517                         continue;
518                     }
519
520                     for(Direction direction : directions) {
521
522                         // When specific direction flows exists, do not create them again
523                         if (direction.equals(Direction.In) && reversePathFlowsCreated) {
524                             continue;
525                         }
526                         if (direction.equals(Direction.Out) && directPathFlowsCreated) {
527                             continue;
528                         }
529
530                         List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant, rule);
531                         List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant, rule);
532
533                         // In case chain action is called here, it has to know that this is reversed policy to set tunnel
534                         // ordinal correctly
535                         List<ActionBuilder> inActions = createActions(ofWriter, netElements, Direction.In, policyPair, tenant,
536                                 rule, isReverted);
537                         List<ActionBuilder> outActions = createActions(ofWriter, netElements, Direction.Out, policyPair, tenant,
538                                 rule, isReverted);
539
540                         createFlows(inMatches, inActions, netElements, ofWriter, priority);
541                         createFlows(outMatches, outActions, netElements, ofWriter, priority);
542
543                         if (direction.equals(Direction.In)) {
544                             reversePathFlowsCreated = true;
545                         }
546                         if (direction.equals(Direction.Out)) {
547                             directPathFlowsCreated = true;
548                         }
549
550                         priority -= 1;
551
552                         if (directPathFlowsCreated && reversePathFlowsCreated) {
553                             resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
554                         }
555                     }
556                 }
557             }
558         }
559     }
560
561     private void allowSameEpg(NodeId nodeId, OfWriter ofWriter) throws Exception {
562         for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
563             for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
564
565                 IndexedTenant tenant = ctx.getTenant(sourceEpgKey.getTenantId());
566                 if (tenant != null) {
567                     EndpointGroup group = tenant.getEndpointGroup(sourceEpgKey.getEgId());
568                     if (group == null) {
569                         LOG.debug("EPG {} does not exit and is used in EP {}", sourceEpgKey, sourceEp.getKey());
570                         continue;
571                     }
572                     IntraGroupPolicy igp = group.getIntraGroupPolicy();
573
574                     if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
575                         for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(sourceEpgKey)) {
576                             EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
577                                     OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
578                             if (srcEpFwdCxtOrdinals == null) {
579                                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
580                                 continue;
581                             }
582
583                             EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
584                                     OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
585                             if (dstEpFwdCxtOrdinals == null) {
586                                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
587                                 continue;
588                             }
589
590                             int destinationEpgId = dstEpFwdCxtOrdinals.getEpgId();
591                             int sourceEpgId = srcEpFwdCxtOrdinals.getEpgId();
592                             ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(sourceEpgId, destinationEpgId));
593                             ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(destinationEpgId, sourceEpgId));
594                         }
595                     }
596                 }
597             }
598         }
599     }
600
601     // Return list of all rules with opposite direction
602     private List<Rule> findRulesInSameDirection(Rule ruleToResolve, List<Rule> reversedRules) {
603         List<Rule> sameDirectionRules = new ArrayList<>();
604         for (Rule ruleToCompare : reversedRules) {
605             for (ClassifierRef classifierRefToCompare : ruleToCompare.getClassifierRef()) {
606                 for (ClassifierRef classifierRefToResolve : ruleToResolve.getClassifierRef()) {
607                     if (isDirectionOpposite(classifierRefToCompare.getDirection(), classifierRefToResolve.getDirection())) {
608                         sameDirectionRules.add(ruleToCompare);
609                     }
610                 }
611             }
612         }
613         return sameDirectionRules;
614     }
615
616     private boolean isDirectionOpposite(Direction one, Direction two) {
617         return ((one.equals(Direction.In) && two.equals(Direction.Out))
618                 || (one.equals(Direction.Out) && two.equals(Direction.In)));
619     }
620
621     private List<Rule> getRules(List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules) {
622         List<Rule> rules = new ArrayList<>();
623         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRule : activeRules) {
624             for (RuleGroup ruleGroup : activeRule.getValue()) {
625                 for (Rule rule : ruleGroup.getRules()) {
626                     rules.add(rule);
627                 }
628             }
629         }
630         return rules;
631     }
632
633     private Flow createArpFlow(Integer fdId) {
634
635         Long etherType = FlowUtils.ARP;
636         // L2 Classifier so 20,000 for now
637         Integer priority = 20000;
638
639         MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
640
641         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
642
643         Match match = mb.build();
644         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
645         return base().setPriority(priority)
646                 .setId(flowid)
647                 .setMatch(match)
648                 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
649                 .build();
650     }
651
652     private Flow allowSameEpg(int sourceEpgId, int destinationEpgId) {
653
654         MatchBuilder mb = new MatchBuilder();
655         addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) sourceEpgId),
656                 RegMatch.of(NxmNxReg2.class, (long) destinationEpgId));
657         Match match = mb.build();
658         FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
659         FlowBuilder flow = base().setId(flowId)
660                 .setMatch(match)
661                 .setPriority(65000)
662                 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
663         return flow.build();
664     }
665
666     private Flow allowFromTunnel(NodeConnectorId tunPort) {
667
668         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
669         addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
670         Match match = mb.build();
671         FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
672         FlowBuilder flow = base().setId(flowId)
673                 .setMatch(match)
674                 .setPriority(65000)
675                 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
676         return flow.build();
677
678     }
679
680     private List<MatchBuilder> createMatches(Direction direction, PolicyPair policyPair, IndexedTenant contractTenant,
681                                              Rule rule) {
682         Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
683         Set<ClassifierDefinitionId> classifiers = new HashSet<>();
684         for (ClassifierRef cr : rule.getClassifierRef()) {
685
686             if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
687                     && !cr.getDirection().equals(direction)) {
688                 continue;
689             }
690
691             // XXX - TODO - implement connection tracking (requires openflow
692             // extension and data plane support - in 2.4. Will need to handle
693             // case where we are working with mix of nodes.
694
695             ClassifierInstance ci = contractTenant.getClassifier(cr.getInstanceName());
696             if (ci == null) {
697                 // XXX TODO fail the match and raise an exception
698                 LOG.warn("Classifier instance {} not found", cr.getInstanceName().getValue());
699                 return null;
700             }
701             Classifier classifier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
702             if (classifier == null) {
703                 // XXX TODO fail the match and raise an exception
704                 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
705                 return null;
706             }
707             classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
708             for (ParameterValue v : ci.getParameterValue()) {
709                 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
710                     if (v.getIntValue() != null || v.getStringValue() != null || v.getRangeValue() != null) {
711                         paramsFromClassifier.put(v.getName().getValue(), v);
712                     }
713                 } else {
714                     if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
715                         throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
716                                 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
717                     }
718                 }
719             }
720         }
721         if (classifiers.isEmpty()) {
722             return null;
723         }
724         List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
725         List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
726         for (Map<String, ParameterValue> params : derivedParamsByName) {
727             List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
728             if (policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
729                 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, null));
730             } else if (!policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
731                 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
732                     matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, null));
733                 }
734             } else if (policyPair.consumerEicIpPrefixes.isEmpty() && !policyPair.providerEicIpPrefixes.isEmpty()) {
735                 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
736                     matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, dIpPrefix));
737                 }
738             } else {
739                 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
740                     for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
741                         matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, dIpPrefix));
742                     }
743                 }
744             }
745             for (ClassifierDefinitionId clDefId : classifiers) {
746                 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
747                 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
748                 if (!result.isSuccessfull()) {
749                     // TODO consider different handling.
750                     throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName()
751                             + ".\nCause: " + result.getErrorMessage());
752                 }
753                 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
754             }
755             flowMatchBuilders.addAll(matchBuildersToResolve);
756         }
757         return flowMatchBuilders;
758     }
759
760     private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction, PolicyPair policyPair,
761                                               IndexedTenant contractTenant, Rule rule, boolean isReversedDirection) {
762         List<ActionBuilder> actionBuilderList = new ArrayList<>();
763         if (rule.getActionRef() != null) {
764
765             // Pre-sort by references using order, then name
766             List<ActionRef> actionRefList = new ArrayList<>(rule.getActionRef());
767             Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
768
769             for (ActionRef actionRule : actionRefList) {
770                 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
771                 if (actionInstance == null) {
772                     // XXX TODO fail the match and raise an exception
773                     LOG.warn("Action instance {} not found", actionRule.getName().getValue());
774                     return null;
775                 }
776                 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
777                 if (action == null) {
778                     // XXX TODO fail the match and raise an exception
779                     LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
780                     return null;
781                 }
782
783                 Map<String, Object> params = new HashMap<>();
784                 if (actionInstance.getParameterValue() != null) {
785                     for (ParameterValue v : actionInstance.getParameterValue()) {
786                         if (v.getName() == null)
787                             continue;
788                         if (v.getIntValue() != null) {
789                             params.put(v.getName().getValue(), v.getIntValue());
790                         } else if (v.getStringValue() != null) {
791                             params.put(v.getName().getValue(), v.getStringValue());
792                         }
793                     }
794                 }
795                 if (isReversedDirection) {
796                     direction = reverse(direction);
797                 }
798
799                 // Convert the GBP Action to one or more OpenFlow Actions
800                 if (!(actionRefList.indexOf(actionRule) == (actionRefList.size() - 1)
801                         && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId())))) {
802                     actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(), netElements,
803                             policyPair, ofWriter, ctx, direction);
804                 }
805             }
806         }
807
808         return actionBuilderList;
809     }
810
811     private Direction reverse(Direction direction) {
812         if (direction.equals(Direction.In)) {
813             return Direction.Out;
814         }
815         else if(direction.equals(Direction.Out)) {
816             return Direction.In;
817         }
818         else {
819             return Direction.Bidirectional;
820         }
821     }
822
823     private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList, NetworkElements netElements,
824                              OfWriter ofWriter, int priority) {
825         FlowBuilder flow = base().setPriority(priority);
826         if(flowMatchBuilders == null) {
827             return;
828         }
829         for (MatchBuilder mb : flowMatchBuilders) {
830             Match match = mb.build();
831             FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "cg", match);
832             flow.setMatch(match).setId(flowId).setPriority(priority);
833
834             // If destination is External, the last Action ALLOW must be changed to goto
835             // NAT/External table.
836             // If actionBuilderList is empty (we removed the last Allow) then go straight to
837             // ExternalMapper table.
838
839             List<ExternalImplicitGroup> eigs = ctx.getTenant(netElements.getDstEp().getTenant())
840                 .getTenant()
841                 .getPolicy()
842                 .getExternalImplicitGroup();
843             if (EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
844                 flow.setInstructions(instructions(gotoEgressNatInstruction));
845             } else if (actionBuilderList == null) {
846                 //TODO - analyse, what happen for unknown action, SFC, etc.
847                 LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
848                 continue;
849             } else if (actionBuilderList.isEmpty()) {
850                 flow.setInstructions(instructions(gotoExternalInstruction));
851             } else {
852                 flow.setInstructions(instructions(applyActionIns(actionBuilderList), gotoExternalInstruction));
853             }
854             ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
855         }
856     }
857
858     private MatchBuilder createBaseMatch(Direction direction, PolicyPair policyPair, IpPrefix sIpPrefix,
859                                          IpPrefix dIpPrefix) {
860         MatchBuilder baseMatch = new MatchBuilder();
861         if (direction.equals(Direction.In)) {
862             addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.consumerEpgId),
863                     RegMatch.of(NxmNxReg1.class, (long) policyPair.consumerCondGrpId),
864                     RegMatch.of(NxmNxReg2.class, (long) policyPair.providerEpgId),
865                     RegMatch.of(NxmNxReg3.class, (long) policyPair.providerCondGrpId));
866             if (sIpPrefix != null) {
867                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
868             }
869             if (dIpPrefix != null) {
870                 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
871             }
872         } else {
873             addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.providerEpgId),
874                     RegMatch.of(NxmNxReg1.class, (long) policyPair.providerCondGrpId),
875                     RegMatch.of(NxmNxReg2.class, (long) policyPair.consumerEpgId),
876                     RegMatch.of(NxmNxReg3.class, (long) policyPair.consumerCondGrpId));
877             if (sIpPrefix != null) {
878                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
879             }
880             if (dIpPrefix != null) {
881                 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
882             }
883         }
884         return baseMatch;
885     }
886
887     private Layer3Match createLayer3Match(IpPrefix ipPrefix, boolean isSrc) {
888         if (ipPrefix.getIpv4Prefix() != null) {
889             if (isSrc) {
890                 return new Ipv4MatchBuilder().setIpv4Source(ipPrefix.getIpv4Prefix()).build();
891             } else {
892                 return new Ipv4MatchBuilder().setIpv4Destination(ipPrefix.getIpv4Prefix()).build();
893             }
894         } else {
895             if (isSrc) {
896                 return new Ipv6MatchBuilder().setIpv6Source(ipPrefix.getIpv6Prefix()).build();
897             } else {
898                 return new Ipv6MatchBuilder().setIpv6Destination(ipPrefix.getIpv6Prefix()).build();
899             }
900         }
901     }
902
903     // TODO: move to a common utils for all renderers
904     private List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
905                                                                                                          Endpoint consEp, Endpoint provEp) {
906         List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
907         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
908             EndpointConstraint consEpConstraint = cell.getRowKey();
909             EndpointConstraint provEpConstraint = cell.getColumnKey();
910             if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
911                 rulesWithEpConstraints.add(cell);
912             }
913         }
914         return rulesWithEpConstraints;
915     }
916
917     private boolean epMatchesConstraint(Endpoint ep, EndpointConstraint constraint) {
918         List<ConditionName> epConditions = Collections.emptyList();
919         if (ep.getCondition() != null) {
920             epConditions = ep.getCondition();
921         }
922         return constraint.getConditionSet().matches(epConditions);
923     }
924
925     private enum PathStatus { both, partial, none }
926
927     public static boolean checkPolicyOrientation() {
928         return isReversedPolicy;
929     }
930
931     /**
932      * Private internal class for ordering Actions in Rules. The order is
933      * determined first by the value of the order parameter, with the lower
934      * order actions being applied first; for Actions with either the same order
935      * or no order, ordering is lexicographical by name.
936      */
937     private static class ActionRefComparator implements Comparator<ActionRef> {
938
939         public static final ActionRefComparator INSTANCE = new ActionRefComparator();
940
941         @Override
942         public int compare(ActionRef arg0, ActionRef arg1) {
943             return ComparisonChain.start()
944                     .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
945                     .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
946                     .result();
947         }
948
949     }
950
951     @Immutable
952     public static class PolicyPair {
953
954         private final int consumerEpgId;
955         private final int providerEpgId;
956         private final int consumerCondGrpId;
957         private final int providerCondGrpId;
958         private final Set<IpPrefix> consumerEicIpPrefixes;
959         private final Set<IpPrefix> providerEicIpPrefixes;
960         private final NodeId consumerEpNodeId;
961         private final NodeId providerEpNodeId;
962
963         public PolicyPair(int consumerEpgId, int providerEpgId, int consumerCondGrpId, int providerCondGrpId,
964                           Set<IpPrefix> consumerEicIpPrefixes, Set<IpPrefix> providerEicIpPrefixes, NodeId consumerEpNodeId, NodeId providerEpNodeId) {
965             super();
966             this.consumerEpgId = consumerEpgId;
967             this.providerEpgId = providerEpgId;
968             this.consumerCondGrpId = consumerCondGrpId;
969             this.providerCondGrpId = providerCondGrpId;
970             this.consumerEicIpPrefixes = consumerEicIpPrefixes;
971             this.providerEicIpPrefixes = providerEicIpPrefixes;
972             this.consumerEpNodeId = consumerEpNodeId;
973             this.providerEpNodeId = providerEpNodeId;
974         }
975
976         public int getConsumerEpgId() {
977             return consumerEpgId;
978         }
979
980         public int getProviderEpgId() {
981             return providerEpgId;
982         }
983
984         public NodeId getConsumerEpNodeId() {
985             return consumerEpNodeId;
986         }
987
988         public NodeId getProviderEpNodeId() {
989             return providerEpNodeId;
990         }
991
992         @Override
993         public int hashCode() {
994             final int prime = 31;
995             int result = 1;
996             result = prime * result + ((providerEicIpPrefixes == null) ? 0 : providerEicIpPrefixes.hashCode());
997             result = prime * result + providerCondGrpId;
998             result = prime * result + providerEpgId;
999             result = prime * result + ((consumerEicIpPrefixes == null) ? 0 : consumerEicIpPrefixes.hashCode());
1000             result = prime * result + consumerCondGrpId;
1001             result = prime * result + consumerEpgId;
1002             result = prime * result + ((consumerEpNodeId == null) ? 0 : consumerEpNodeId.hashCode());
1003             result = prime * result + ((providerEpNodeId == null) ? 0 : providerEpNodeId.hashCode());
1004
1005             return result;
1006         }
1007
1008         @Override
1009         public boolean equals(Object obj) {
1010             if (this == obj)
1011                 return true;
1012             if (obj == null)
1013                 return false;
1014             if (getClass() != obj.getClass())
1015                 return false;
1016             PolicyPair other = (PolicyPair) obj;
1017             if (providerEicIpPrefixes == null) {
1018                 if (other.providerEicIpPrefixes != null) {
1019                     return false;
1020                 }
1021             } else if (!providerEicIpPrefixes.equals(other.providerEicIpPrefixes)) {
1022                 return false;
1023             }
1024             if (consumerEicIpPrefixes == null) {
1025                 if (other.consumerEicIpPrefixes != null) {
1026                     return false;
1027                 }
1028             } else if (!consumerEicIpPrefixes.equals(other.consumerEicIpPrefixes)) {
1029                 return false;
1030             }
1031             if (consumerEpNodeId == null) {
1032                 if (other.consumerEpNodeId != null) {
1033                     return false;
1034                 }
1035             } else if (!consumerEpNodeId.getValue().equals(other.consumerEpNodeId.getValue())) {
1036                 return false;
1037             }
1038             if (providerEpNodeId == null) {
1039                 if (other.providerEpNodeId != null) {
1040                     return false;
1041                 }
1042             } else if (!providerEpNodeId.getValue().equals(other.providerEpNodeId.getValue())) {
1043                 return false;
1044             }
1045             return (providerCondGrpId == other.providerCondGrpId)
1046                     && (providerEpgId == other.providerEpgId)
1047                     && (consumerCondGrpId == other.consumerCondGrpId)
1048                     && (consumerEpgId == other.consumerEpgId);
1049
1050         }
1051
1052         @Override
1053         public String toString() {
1054             return "consumerEPG: " + consumerEpgId +
1055                     "consumerCG: " + consumerCondGrpId +
1056                     "providerEPG: " + providerEpgId +
1057                     "providerCG: " + providerCondGrpId +
1058                     "consumerEpNodeId: " + consumerEpNodeId +
1059                     "providerEpNodeId: " + providerEpNodeId +
1060                     "consumerEicIpPrefixes: " + consumerEicIpPrefixes +
1061                     "providerEicIpPrefixes: " + providerEicIpPrefixes;
1062         }
1063     }
1064
1065     public class NetworkElements {
1066
1067         private final Endpoint srcEp;
1068         private final Endpoint dstEp;
1069         private final EgKey srcEpg;
1070         private final EgKey dstEpg;
1071         private NodeId srcNodeId;
1072         private NodeId dstNodeId;
1073         private final NodeId localNodeId;
1074         private EndpointFwdCtxOrdinals srcEpOrdinals;
1075         private EndpointFwdCtxOrdinals dstEpOrdinals;
1076
1077         public NetworkElements(Endpoint srcEp, Endpoint dstEp, EgKey srcEpg, EgKey dstEpg, NodeId nodeId, OfContext ctx) throws Exception {
1078             this.srcEp = srcEp;
1079             this.dstEp = dstEp;
1080             this.srcEpg = srcEpg;
1081             this.dstEpg = dstEpg;
1082             this.localNodeId = nodeId;
1083             this.srcEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);
1084             if (this.srcEpOrdinals == null) {
1085                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
1086                 return;
1087             }
1088             this.dstEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
1089             if (this.dstEpOrdinals == null) {
1090                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
1091                 return;
1092             }
1093             if (dstEp.getAugmentation(OfOverlayContext.class) != null) {
1094                 this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();
1095             }
1096             if (srcEp.getAugmentation(OfOverlayContext.class) != null) {
1097                 this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();
1098             }
1099         }
1100
1101
1102         public Endpoint getSrcEp() {
1103             return srcEp;
1104         }
1105
1106
1107         public Endpoint getDstEp() {
1108             return dstEp;
1109         }
1110
1111         public EgKey getSrcEpg() {
1112             return srcEpg;
1113         }
1114
1115         public EgKey getDstEpg() {
1116             return dstEpg;
1117         }
1118
1119         public NodeId getSrcNodeId() {
1120             return srcNodeId;
1121         }
1122
1123
1124         public NodeId getDstNodeId() {
1125             return dstNodeId;
1126         }
1127
1128
1129         public NodeId getLocalNodeId() {
1130             return localNodeId;
1131         }
1132
1133
1134         public EndpointFwdCtxOrdinals getSrcEpOrdinals() {
1135             return srcEpOrdinals;
1136         }
1137
1138
1139         public EndpointFwdCtxOrdinals getDstEpOrdinals() {
1140             return dstEpOrdinals;
1141         }
1142
1143
1144     }
1145 }