Move definitions of classifiers and actions to
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / PolicyEnforcer.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
10
11 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
16
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import javax.annotation.concurrent.Immutable;
27
28 import org.opendaylight.groupbasedpolicy.sf.actions.AllowActionDefinition;
29 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
30 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
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         PolicyEnforcer.TABLE_ID = tableId;
102         PolicyEnforcer.gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
103         PolicyEnforcer.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, OfWriter ofWriter) throws Exception {
113
114         ofWriter.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             ofWriter.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                         if (srcEpFwdCxtOrds == null) {
139                             LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
140                             continue;
141                         }
142
143                         EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
144                                 policyInfo, dstEp);
145                         if (dstEpFwdCxtOrds == null) {
146                             LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
147                             continue;
148                         }
149
150                         int dcgId = dstEpFwdCxtOrds.getCgId();
151                         int depgId = dstEpFwdCxtOrds.getEpgId();
152                         int scgId = srcEpFwdCxtOrds.getCgId();
153                         int sepgId = srcEpFwdCxtOrds.getEpgId();
154
155                         fdIds.add(srcEpFwdCxtOrds.getFdId());
156                         NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
157
158                         Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
159                         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
160                                 policy, dstEp, srcEp)) {
161                             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
162                                 .getL3EpPrefixes());
163                             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
164                                 .getL3EpPrefixes());
165                             PolicyPair policyPair = new PolicyPair(depgId, sepgId, dcgId, scgId, dIpPrefixes,
166                                     sIpPrefixes, netElements.getDstNodeId(), netElements.getSrcNodeId());
167                             if (visitedPairs.contains(policyPair)) {
168                                 LOG.trace("PolicyEnforcer: Already visited PolicyPair {}, endpoints {} {} skipped",
169                                         policyPair, srcEp.getKey(), dstEp.getKey());
170                                 continue;
171                             } else {
172                                 LOG.trace("PolicyEnforcer: Visiting PolicyPair {} endpoints {} {}", policyPair,
173                                         srcEp.getKey(), dstEp.getKey());
174                                 visitedPairs.add(policyPair);
175                             }
176                             syncPolicy(ofWriter, netElements, activeRulesByConstraints.getValue(), policyPair);
177                         }
178
179                         // Reverse
180                         policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
181                         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
182                                 policy, srcEp, dstEp)) {
183                             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
184                                 .getL3EpPrefixes());
185                             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
186                                 .getL3EpPrefixes());
187                             PolicyPair policyPair = new PolicyPair(sepgId, depgId, scgId, dcgId, sIpPrefixes,
188                                     dIpPrefixes, netElements.getSrcNodeId(), netElements.getDstNodeId());
189                             if (visitedReversePairs.contains(policyPair)) {
190                                 LOG.trace(
191                                         "PolicyEnforcer: Reverse: Already visited PolicyPair {}, endpoints {} {} skipped",
192                                         policyPair, srcEp.getKey(), dstEp.getKey());
193                                 continue;
194                             } else {
195                                 LOG.trace("PolicyEnforcer: Reverse: Visiting: PolicyPair {} via endpoints {} {}",
196                                         policyPair, srcEp.getKey(), dstEp.getKey());
197                                 visitedReversePairs.add(policyPair);
198
199                             }
200                             syncPolicy(ofWriter, netElements, activeRulesByConstraints.getValue(), policyPair);
201                         }
202                     }
203                 }
204             }
205         }
206
207         // Allow same EPG
208         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
209             for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
210
211                 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
212                 if (tenant != null) {
213                     EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
214                     if (group == null) {
215                         LOG.debug("EPG {} does not exit and is used in EP {}", srcEpgKey, srcEp.getKey());
216                         continue;
217                     }
218                     IntraGroupPolicy igp = group.getIntraGroupPolicy();
219
220                     if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
221                         for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
222                             EndpointFwdCtxOrdinals srcEpFwdCxtOrds =
223                                 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
224                             if (srcEpFwdCxtOrds == null) {
225                                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
226                                 continue;
227                             }
228
229                             EndpointFwdCtxOrdinals dstEpFwdCxtOrds =
230                                 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dstEp);
231                             if (dstEpFwdCxtOrds == null) {
232                                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
233                                 continue;
234                             }
235
236                             int depgId = dstEpFwdCxtOrds.getEpgId();
237                             int sepgId = srcEpFwdCxtOrds.getEpgId();
238                             ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
239                             ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
240                         }
241                     }
242                 }
243             }
244         }
245
246         // Write ARP flows per flood domain.
247         for (Integer fdId : fdIds) {
248             ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
249         }
250     }
251
252     private Flow createArpFlow(Integer fdId) {
253
254         Long etherType = FlowUtils.ARP;
255         // L2 Classifier so 20,000 for now
256         Integer priority = 20000;
257
258         MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
259
260         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
261
262         Match match = mb.build();
263         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
264         Flow flow = base().setPriority(priority)
265             .setId(flowid)
266             .setMatch(match)
267             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
268             .build();
269         return flow;
270     }
271
272     private Flow allowSameEpg(int sepgId, int depgId) {
273
274         MatchBuilder mb = new MatchBuilder();
275         addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
276                 RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
277         Match match = mb.build();
278         FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
279         FlowBuilder flow = base().setId(flowId)
280             .setMatch(match)
281             .setPriority(65000)
282             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
283         return flow.build();
284     }
285
286     private Flow allowFromTunnel(NodeConnectorId tunPort) {
287
288         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
289         addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
290         Match match = mb.build();
291         FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
292         FlowBuilder flow = base().setId(flowId)
293             .setMatch(match)
294             .setPriority(65000)
295             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
296         return flow.build();
297
298     }
299
300     private void syncPolicy(OfWriter ofWriter, NetworkElements netElements, List<RuleGroup> rgs, PolicyPair policyPair) {
301         int priority = 65000;
302         for (RuleGroup rg : rgs) {
303             TenantId tenantId = rg.getContractTenant().getId();
304             IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
305             for (Rule r : rg.getRules()) {
306                 syncDirection(ofWriter, netElements, tenant, policyPair, r, Direction.In, priority);
307                 syncDirection(ofWriter, netElements, tenant, policyPair, r, Direction.Out, priority);
308
309                 priority -= 1;
310             }
311         }
312     }
313
314     /**
315      * Private internal class for ordering Actions in Rules. The order is
316      * determined first by the value of the order parameter, with the lower
317      * order actions being applied first; for Actions with either the same order
318      * or no order, ordering is lexicographical by name.
319      */
320     private static class ActionRefComparator implements Comparator<ActionRef> {
321
322         public static final ActionRefComparator INSTANCE = new ActionRefComparator();
323
324         @Override
325         public int compare(ActionRef arg0, ActionRef arg1) {
326             return ComparisonChain.start()
327                 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
328                 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
329                 .result();
330         }
331
332     }
333
334     private void syncDirection(OfWriter ofWriter, NetworkElements netElements, IndexedTenant contractTenant,
335             PolicyPair policyPair, Rule rule, Direction direction, int priority) {
336
337
338         Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
339         Set<ClassifierDefinitionId> classifiers = new HashSet<>();
340         for (ClassifierRef cr : rule.getClassifierRef()) {
341             if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
342                     && !cr.getDirection().equals(direction)) {
343                 continue;
344             }
345
346             // XXX - TODO - implement connection tracking (requires openflow
347             // extension and data plane support - in 2.4. Will need to handle
348             // case where we are working with mix of nodes.
349
350             ClassifierInstance ci = contractTenant.getClassifier(cr.getInstanceName());
351             if (ci == null) {
352                 // XXX TODO fail the match and raise an exception
353                 LOG.warn("Classifier instance {} not found", cr.getInstanceName().getValue());
354                 return;
355             }
356             Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
357             if (cfier == null) {
358                 // XXX TODO fail the match and raise an exception
359                 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
360                 return;
361             }
362             classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
363             for (ParameterValue v : ci.getParameterValue()) {
364                 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
365                     if (v.getIntValue() != null || v.getStringValue() != null || v.getRangeValue() != null) {
366                         paramsFromClassifier.put(v.getName().getValue(), v);
367                     }
368                 } else {
369                     if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
370                         throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
371                                 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
372                     }
373                 }
374             }
375         }
376         if (classifiers.isEmpty()) {
377             return;
378         }
379         List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
380         List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
381         for (Map<String, ParameterValue> params : derivedParamsByName) {
382             List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
383             if (policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
384                 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, null));
385             } else if (!policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
386                 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
387                     matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, null));
388                 }
389             } else if (policyPair.consumerEicIpPrefixes.isEmpty() && !policyPair.providerEicIpPrefixes.isEmpty()) {
390                 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
391                     matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, dIpPrefix));
392                 }
393             } else {
394                 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
395                     for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
396                         matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, dIpPrefix));
397                     }
398                 }
399             }
400             for (ClassifierDefinitionId clDefId : classifiers) {
401                 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
402                 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
403                 if (!result.isSuccessfull()) {
404                     // TODO consider different handling.
405                     throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName()
406                             + ".\nCause: " + result.getErrorMessage());
407                 }
408                 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
409             }
410             flowMatchBuilders.addAll(matchBuildersToResolve);
411         }
412
413         /*
414          * Create the ordered action list. The implicit action is "allow", and
415          * is therefore always in the list
416          */
417
418         List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
419         if (rule.getActionRef() != null) {
420             /*
421              * Pre-sort by references using order, then name
422              */
423             List<ActionRef> actionRefList = new ArrayList<ActionRef>(rule.getActionRef());
424             Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
425
426             for (ActionRef actionRule : actionRefList) {
427                 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
428                 if (actionInstance == null) {
429                     // XXX TODO fail the match and raise an exception
430                     LOG.warn("Action instance {} not found", actionRule.getName().getValue());
431                     return;
432                 }
433                 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
434                 if (action == null) {
435                     // XXX TODO fail the match and raise an exception
436                     LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
437                     return;
438                 }
439
440                 Map<String, Object> params = new HashMap<>();
441                 if (actionInstance.getParameterValue() != null) {
442                     for (ParameterValue v : actionInstance.getParameterValue()) {
443                         if (v.getName() == null)
444                             continue;
445                         if (v.getIntValue() != null) {
446                             params.put(v.getName().getValue(), v.getIntValue());
447                         } else if (v.getStringValue() != null) {
448                             params.put(v.getName().getValue(), v.getStringValue());
449                         }
450                     }
451                 }
452                 /*
453                  * Convert the GBP Action to one or more OpenFlow Actions
454                  */
455                 if (!(actionRefList.indexOf(actionRule) == (actionRefList.size() - 1) && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId())))) {
456                     actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(), netElements, policyPair,
457                             ofWriter, ctx, direction);
458                 }
459             }
460         }
461         FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
462         for (MatchBuilder mb : flowMatchBuilders) {
463             Match match = mb.build();
464             FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "cg", match);
465             flow.setMatch(match).setId(flowId).setPriority(Integer.valueOf(priority));
466
467             /*
468              * If destination is External, the last Action ALLOW must be changed to goto
469              * NAT/External table.
470              * If actionBuilderList is empty (we removed the last Allow) then go straight to
471              * ExternalMapper table.
472              */
473
474             if (ctx.getEndpointManager().isExternal(netElements.getDstEp())) {
475                 flow.setInstructions(instructions(getGotoEgressNatInstruction()));
476             } else if (actionBuilderList == null) {
477                 //TODO - analyse, what happen for unknown action, SFC, etc.
478                 LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
479                 continue;
480             } else if (actionBuilderList.isEmpty()) {
481                 flow.setInstructions(instructions(getGotoExternalInstruction()));
482             } else {
483                 flow.setInstructions(instructions(applyActionIns(actionBuilderList), getGotoExternalInstruction()));
484             }
485             ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
486         }
487     }
488
489     private MatchBuilder createBaseMatch(Direction direction, PolicyPair policyPair, IpPrefix sIpPrefix,
490             IpPrefix dIpPrefix) {
491         MatchBuilder baseMatch = new MatchBuilder();
492         if (direction.equals(Direction.In)) {
493             addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(policyPair.consumerEpgId)),
494                     RegMatch.of(NxmNxReg1.class, Long.valueOf(policyPair.consumerCondGrpId)),
495                     RegMatch.of(NxmNxReg2.class, Long.valueOf(policyPair.providerEpgId)),
496                     RegMatch.of(NxmNxReg3.class, Long.valueOf(policyPair.providerCondGrpId)));
497             if (sIpPrefix != null) {
498                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
499             }
500             if (dIpPrefix != null) {
501                 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
502             }
503         } else {
504             addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(policyPair.providerEpgId)),
505                     RegMatch.of(NxmNxReg1.class, Long.valueOf(policyPair.providerCondGrpId)),
506                     RegMatch.of(NxmNxReg2.class, Long.valueOf(policyPair.consumerEpgId)),
507                     RegMatch.of(NxmNxReg3.class, Long.valueOf(policyPair.consumerCondGrpId)));
508             if (sIpPrefix != null) {
509                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
510             }
511             if (dIpPrefix != null) {
512                 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
513             }
514         }
515         return baseMatch;
516     }
517
518     private Layer3Match createLayer3Match(IpPrefix ipPrefix, boolean isSrc) {
519         if (ipPrefix.getIpv4Prefix() != null) {
520             if (isSrc) {
521                 return new Ipv4MatchBuilder().setIpv4Source(ipPrefix.getIpv4Prefix()).build();
522             } else {
523                 return new Ipv4MatchBuilder().setIpv4Destination(ipPrefix.getIpv4Prefix()).build();
524             }
525         } else {
526             if (isSrc) {
527                 return new Ipv6MatchBuilder().setIpv6Source(ipPrefix.getIpv6Prefix()).build();
528             } else {
529                 return new Ipv6MatchBuilder().setIpv6Destination(ipPrefix.getIpv6Prefix()).build();
530             }
531         }
532     }
533
534     // TODO: move to a common utils for all renderers
535     public List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
536             Endpoint consEp, Endpoint provEp) {
537         List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
538         if (policy.getRuleMap() != null) {
539             for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
540                 EndpointConstraint consEpConstraint = cell.getRowKey();
541                 EndpointConstraint provEpConstraint = cell.getColumnKey();
542                 if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
543                     rulesWithEpConstraints.add(cell);
544                 }
545             }
546         }
547         return rulesWithEpConstraints;
548     }
549
550     private boolean epMatchesConstraint(Endpoint ep, EndpointConstraint constraint) {
551         List<ConditionName> epConditions = Collections.emptyList();
552         if (ep.getCondition() != null) {
553             epConditions = ep.getCondition();
554         }
555         return constraint.getConditionSet().matches(epConditions);
556     }
557
558     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
559         return gotoEgressNatInstruction;
560     }
561
562     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
563         return gotoExternalInstruction;
564     }
565
566     @Immutable
567     public static class PolicyPair {
568
569         private final int consumerEpgId;
570         private final int providerEpgId;
571         private final int consumerCondGrpId;
572         private final int providerCondGrpId;
573         private final Set<IpPrefix> consumerEicIpPrefixes;
574         private final Set<IpPrefix> providerEicIpPrefixes;
575         private NodeId consumerEpNodeId;
576         private NodeId providerEpNodeId;
577
578         public int getConsumerEpgId() {
579             return consumerEpgId;
580         }
581
582         public int getProviderEpgId() {
583             return providerEpgId;
584         }
585
586         public NodeId getConsumerEpNodeId() {
587             return consumerEpNodeId;
588         }
589
590         public NodeId getProviderEpNodeId() {
591             return providerEpNodeId;
592         }
593
594         public PolicyPair(int consumerEpgId, int providerEpgId, int consumerCondGrpId, int providerCondGrpId,
595                 Set<IpPrefix> consumerEicIpPrefixes, Set<IpPrefix> providerEicIpPrefixes, NodeId consumerEpNodeId, NodeId providerEpNodeId) {
596             super();
597             this.consumerEpgId = consumerEpgId;
598             this.providerEpgId = providerEpgId;
599             this.consumerCondGrpId = consumerCondGrpId;
600             this.providerCondGrpId = providerCondGrpId;
601             this.consumerEicIpPrefixes = consumerEicIpPrefixes;
602             this.providerEicIpPrefixes = providerEicIpPrefixes;
603             this.consumerEpNodeId = consumerEpNodeId;
604             this.providerEpNodeId = providerEpNodeId;
605         }
606
607         @Override
608         public int hashCode() {
609             final int prime = 31;
610             int result = 1;
611             result = prime * result + ((providerEicIpPrefixes == null) ? 0 : providerEicIpPrefixes.hashCode());
612             result = prime * result + providerCondGrpId;
613             result = prime * result + providerEpgId;
614             result = prime * result + ((consumerEicIpPrefixes == null) ? 0 : consumerEicIpPrefixes.hashCode());
615             result = prime * result + consumerCondGrpId;
616             result = prime * result + consumerEpgId;
617             result = prime * result + ((consumerEpNodeId == null) ? 0 : consumerEpNodeId.hashCode());
618             result = prime * result + ((providerEpNodeId == null) ? 0 : providerEpNodeId.hashCode());
619
620             return result;
621         }
622
623         @Override
624         public boolean equals(Object obj) {
625             if (this == obj)
626                 return true;
627             if (obj == null)
628                 return false;
629             if (getClass() != obj.getClass())
630                 return false;
631             PolicyPair other = (PolicyPair) obj;
632             if (providerEicIpPrefixes == null) {
633                 if (other.providerEicIpPrefixes != null) {
634                     return false;
635                 }
636             } else if (!providerEicIpPrefixes.equals(other.providerEicIpPrefixes)) {
637                 return false;
638             }
639             if (consumerEicIpPrefixes == null) {
640                 if (other.consumerEicIpPrefixes != null) {
641                     return false;
642                 }
643             } else if (!consumerEicIpPrefixes.equals(other.consumerEicIpPrefixes)) {
644                 return false;
645             }
646             if (consumerEpNodeId == null) {
647                 if (other.consumerEpNodeId != null) {
648                     return false;
649                 }
650             } else if (!consumerEpNodeId.getValue().equals(other.consumerEpNodeId.getValue())) {
651                 return false;
652             }
653             if (providerEpNodeId == null) {
654                 if (other.providerEpNodeId != null) {
655                     return false;
656                 }
657             } else if (!providerEpNodeId.getValue().equals(other.providerEpNodeId.getValue())) {
658                 return false;
659             }
660             if (providerCondGrpId != other.providerCondGrpId)
661                 return false;
662             if (providerEpgId != other.providerEpgId)
663                 return false;
664             if (consumerCondGrpId != other.consumerCondGrpId)
665                 return false;
666             if (consumerEpgId != other.consumerEpgId)
667                 return false;
668
669             return true;
670         }
671
672         @Override
673         public String toString() {
674             return new StringBuilder().append("consumerEPG: ")
675                 .append(consumerEpgId)
676                 .append("consumerCG: ")
677                 .append(consumerCondGrpId)
678                 .append("providerEPG: ")
679                 .append(providerEpgId)
680                 .append("providerCG: ")
681                 .append(providerCondGrpId)
682                 .append("consumerEpNodeId: ")
683                 .append(consumerEpNodeId)
684                 .append("providerEpNodeId: ")
685                 .append(providerEpNodeId)
686                 .append("consumerEicIpPrefixes: ")
687                 .append(consumerEicIpPrefixes)
688                 .append("providerEicIpPrefixes: ")
689                 .append(providerEicIpPrefixes)
690                 .toString();
691         }
692     }
693
694     public class NetworkElements {
695
696         private Endpoint srcEp;
697         private Endpoint dstEp;
698         private NodeId srcNodeId;
699         private NodeId dstNodeId;
700         private NodeId localNodeId;
701         private EndpointFwdCtxOrdinals srcEpOrds;
702         private EndpointFwdCtxOrdinals dstEpOrds;
703
704         public NetworkElements(Endpoint srcEp, Endpoint dstEp, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo)
705                 throws Exception {
706             Preconditions.checkArgument(srcEp.getAugmentation(OfOverlayContext.class) != null);
707             Preconditions.checkArgument(dstEp.getAugmentation(OfOverlayContext.class) != null);
708
709             this.srcEp = srcEp;
710             this.dstEp = dstEp;
711             this.localNodeId = nodeId;
712             this.srcEpOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
713             if (this.srcEpOrds == null) {
714                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
715                 return;
716             }
717             this.dstEpOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dstEp);
718             if (this.dstEpOrds == null) {
719                 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
720                 return;
721             }
722             this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();
723             this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();
724         }
725
726
727         public Endpoint getSrcEp() {
728             return srcEp;
729         }
730
731
732         Endpoint getDstEp() {
733             return dstEp;
734         }
735
736
737         public NodeId getSrcNodeId() {
738             return srcNodeId;
739         }
740
741
742         public NodeId getDstNodeId() {
743             return dstNodeId;
744         }
745
746
747         public NodeId getLocalNodeId() {
748             return localNodeId;
749         }
750
751
752         public EndpointFwdCtxOrdinals getSrcEpOrds() {
753             return srcEpOrds;
754         }
755
756
757         public EndpointFwdCtxOrdinals getDstEpOrds() {
758             return dstEpOrds;
759         }
760
761
762
763     }
764 }