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