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