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