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