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