Bug 2814 - logical OR to AND in classifier
[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.instructions;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
15
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 import javax.annotation.concurrent.Immutable;
26
27 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
28 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
29 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
30 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
31 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
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.policy.rev140421.HasDirection.Direction;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 import com.google.common.collect.ComparisonChain;
80 import com.google.common.collect.Ordering;
81 import com.google.common.collect.Table.Cell;
82
83 /**
84  * Manage the table that enforces policy on the traffic. Traffic is denied
85  * unless specifically allowed by policy
86  */
87 public class PolicyEnforcer extends FlowTable {
88
89     protected static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
90
91     public static short TABLE_ID = 3;
92
93     public PolicyEnforcer(OfContext ctx, short tableId) {
94         super(ctx);
95         this.TABLE_ID=tableId;
96     }
97
98
99     @Override
100     public short getTableId() {
101         return TABLE_ID;
102     }
103
104     @Override
105     public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
106
107         flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
108
109         NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class);
110         if (tunPort != null) {
111             flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
112         }
113
114         HashSet<CgPair> visitedPairs = new HashSet<>();
115
116         // Used for ARP flows
117         Set<Integer> fdIds = new HashSet<>();
118
119         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
120             for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
121                 Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
122                 for (EgKey dstEpgKey : peers) {
123                     for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey)) {
124                         // mEPG ordinals
125                         EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
126                                 policyInfo, srcEp);
127                         EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
128                                 policyInfo, dstEp);
129                         int dcgId = dstEpFwdCxtOrds.getCgId();
130                         int depgId = dstEpFwdCxtOrds.getEpgId();
131                         int scgId = srcEpFwdCxtOrds.getCgId();
132                         int sepgId = srcEpFwdCxtOrds.getEpgId();
133                         NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
134                         fdIds.add(srcEpFwdCxtOrds.getFdId());
135
136                         Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
137                         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints: getActiveRulesBetweenEps(policy, dstEp, srcEp)) {
138                             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
139                                 .getL3EpPrefixes());
140                             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
141                                 .getL3EpPrefixes());
142                             CgPair p = new CgPair(depgId, sepgId, dcgId, scgId, dIpPrefixes, sIpPrefixes);
143                             if (visitedPairs.contains(p))
144                                 continue;
145                             visitedPairs.add(p);
146                             syncPolicy(flowMap, netElements, activeRulesByConstraints.getValue(), p);
147                         }
148
149                         // Reverse
150                         policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
151                         for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(policy, srcEp, dstEp)) {
152                             Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
153                                 .getL3EpPrefixes());
154                             Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
155                                 .getL3EpPrefixes());
156                             CgPair p = new CgPair(sepgId, depgId, scgId, dcgId, sIpPrefixes, dIpPrefixes);
157                             if (visitedPairs.contains(p))
158                                 continue;
159                             visitedPairs.add(p);
160                             syncPolicy(flowMap, netElements, activeRulesByConstraints.getValue(), p);
161                         }
162                     }
163                 }
164             }
165         }
166
167         // Allow same EPG
168         // Set<Endpoint> visitedEps = new HashSet<>();
169         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
170             // visitedEps.add(srcEp);
171             for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
172
173                 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
174                 EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
175                 IntraGroupPolicy igp = group.getIntraGroupPolicy();
176
177                 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
178                     for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
179                         // mEPG ordinals
180                         // if(visitedEps.contains(dstEp)) {
181                         // continue;
182                         // }
183                         // visitedEps.add(dstEp);
184                         EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
185                                 policyInfo, srcEp);
186                         EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
187                                 policyInfo, dstEp);
188                         int depgId = dstEpFwdCxtOrds.getEpgId();
189                         int sepgId = srcEpFwdCxtOrds.getEpgId();
190                         flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
191                         flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
192                     }
193                 }
194             }
195         }
196
197         // Write ARP flows per flood domain.
198         for (Integer fdId : fdIds) {
199             flowMap.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
200         }
201     }
202
203     private Flow createArpFlow(Integer fdId) {
204
205         Long etherType = FlowUtils.ARP;
206         // L2 Classifier so 20,000 for now
207         Integer priority = 20000;
208         FlowId flowid = new FlowId(new StringBuilder().append("arp")
209             .append("|")
210             .append(etherType)
211             .append("|")
212             .append(fdId)
213             .toString());
214
215         MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
216
217         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
218
219         Flow flow = base().setPriority(priority)
220             .setId(flowid)
221             .setMatch(mb.build())
222             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
223             .build();
224         return flow;
225     }
226
227     private Flow allowSameEpg(int sepgId, int depgId) {
228
229         FlowId flowId = new FlowId(new StringBuilder().append("intraallow|").append(sepgId).toString());
230         MatchBuilder mb = new MatchBuilder();
231         addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
232                 RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
233         FlowBuilder flow = base().setId(flowId)
234             .setMatch(mb.build())
235             .setPriority(65000)
236             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
237         return flow.build();
238     }
239
240     private Flow allowFromTunnel(NodeConnectorId tunPort) {
241
242         FlowId flowId = new FlowId("tunnelallow");
243         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
244         addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
245         FlowBuilder flow = base().setId(flowId)
246             .setMatch(mb.build())
247             .setPriority(65000)
248             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
249         return flow.build();
250
251     }
252
253     private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> rgs, CgPair p) {
254         int priority = 65000;
255         for (RuleGroup rg : rgs) {
256             TenantId tenantId = rg.getContractTenant().getId();
257             IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
258             for (Rule r : rg.getRules()) {
259                 syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority);
260                 syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority);
261
262                 priority -= 1;
263             }
264         }
265     }
266
267     /**
268      * Private internal class for ordering Actions in Rules. The order is
269      * determined first by the value of the order parameter, with the lower
270      * order actions being applied first; for Actions with either the same order
271      * or no order, ordering is lexicographical by name.
272      */
273     private static class ActionRefComparator implements Comparator<ActionRef> {
274
275         public static final ActionRefComparator INSTANCE = new ActionRefComparator();
276
277         @Override
278         public int compare(ActionRef arg0, ActionRef arg1) {
279             return ComparisonChain.start()
280                 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
281                 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
282                 .result();
283         }
284
285     }
286
287     private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
288             Direction direction, int priority) {
289         /*
290          * Create the ordered action list. The implicit action is "allow", and
291          * is therefore always in the list
292          *
293          * TODO: revisit implicit vs. default for "allow" TODO: look into
294          * incorporating operational policy for actions
295          */
296
297         // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
298         // referencing in sort
299         List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
300         if (rule.getActionRef() != null) {
301             /*
302              * Pre-sort by references using order, then name
303              */
304             List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
305             Collections.sort(arl, ActionRefComparator.INSTANCE);
306
307             for (ActionRef actionRule : arl) {
308                 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
309                 if (actionInstance == null) {
310                     // XXX TODO fail the match and raise an exception
311                     LOG.warn("Action instance {} not found", actionRule.getName().getValue());
312                     return;
313                 }
314                 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
315                 if (action == null) {
316                     // XXX TODO fail the match and raise an exception
317                     LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
318                     return;
319                 }
320
321                 Map<String, Object> params = new HashMap<>();
322                 if (actionInstance.getParameterValue() != null) {
323                     for (ParameterValue v : actionInstance.getParameterValue()) {
324                         if (v.getName() == null)
325                             continue;
326                         if (v.getIntValue() != null) {
327                             params.put(v.getName().getValue(), v.getIntValue());
328                         } else if (v.getStringValue() != null) {
329                             params.put(v.getName().getValue(), v.getStringValue());
330                         }
331                     }
332                 }
333                 /*
334                  * Convert the GBP Action to one or more OpenFlow Actions
335                  */
336                 actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements);
337             }
338         } else {
339             Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
340             actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
341         }
342
343         Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
344         Set<ClassifierDefinitionId> classifiers = new HashSet<>();
345         for (ClassifierRef cr : rule.getClassifierRef()) {
346             if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
347                     && !cr.getDirection().equals(direction)) {
348                 continue;
349             }
350
351             // XXX - TODO - implement connection tracking (requires openflow
352             // extension and data plane support - in 2.4. Will need to handle
353             // case where we are working with mix of nodes.
354
355             ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
356             if (ci == null) {
357                 // XXX TODO fail the match and raise an exception
358                 LOG.warn("Classifier instance {} not found", cr.getName().getValue());
359                 return;
360             }
361             Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
362             if (cfier == null) {
363                 // XXX TODO fail the match and raise an exception
364                 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
365                 return;
366             }
367             classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
368             for (ParameterValue v : ci.getParameterValue()) {
369                 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
370                     if (v.getIntValue() != null
371                             || v.getStringValue() != null
372                             || v.getRangeValue() != null) {
373                         paramsFromClassifier.put(v.getName().getValue(), v);
374                     }
375                 } else {
376                     if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
377                         throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
378                                 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
379                     }
380                 }
381             }
382         }
383         if(classifiers.isEmpty()) {
384             return;
385         }
386         List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
387         String baseId = createBaseFlowId(direction, cgPair, priority);
388         List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
389         for (Map<String, ParameterValue> params : derivedParamsByName) {
390             List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
391             if (cgPair.sIpPrefixes.isEmpty() && cgPair.dIpPrefixes.isEmpty()) {
392                 matchBuildersToResolve.add(createBaseMatch(direction, cgPair, null, null));
393             } else if (!cgPair.sIpPrefixes.isEmpty() && cgPair.dIpPrefixes.isEmpty()) {
394                 for (IpPrefix sIpPrefix : cgPair.sIpPrefixes) {
395                     matchBuildersToResolve.add(createBaseMatch(direction, cgPair, sIpPrefix, null));
396                 }
397             } else if (cgPair.sIpPrefixes.isEmpty() && !cgPair.dIpPrefixes.isEmpty()) {
398                 for (IpPrefix dIpPrefix : cgPair.sIpPrefixes) {
399                     matchBuildersToResolve.add(createBaseMatch(direction, cgPair, null, dIpPrefix));
400                 }
401             } else {
402                 for (IpPrefix sIpPrefix : cgPair.sIpPrefixes) {
403                     for (IpPrefix dIpPrefix : cgPair.sIpPrefixes) {
404                         matchBuildersToResolve.add(createBaseMatch(direction, cgPair, sIpPrefix, dIpPrefix));
405                     }
406                 }
407             }
408             for (ClassifierDefinitionId clDefId : classifiers) {
409                 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
410                 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
411                 if (!result.isSuccessfull()) {
412                     // TODO consider different handling.
413                     throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName() + ".\nCause: "
414                             + result.getErrorMessage());
415                 }
416                 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
417             }
418             flowMatchBuilders.addAll(matchBuildersToResolve);
419         }
420                 FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
421                 for (MatchBuilder match : flowMatchBuilders) {
422                     Match m = match.build();
423                     FlowId flowId = new FlowId(baseId + "|" + m.toString());
424                     flow.setMatch(m)
425                         .setId(flowId)
426                         .setPriority(Integer.valueOf(priority))
427                         .setInstructions(instructions(applyActionIns(actionBuilderList)));
428                     flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build());
429                 }
430     }
431
432     private String createBaseFlowId(Direction direction, CgPair cgPair, int priority) {
433         StringBuilder idb = new StringBuilder();
434         if (direction.equals(Direction.In)) {
435             idb.append(cgPair.sepg)
436                     .append("|")
437                     .append(cgPair.scgId)
438                     .append("|")
439                     .append(cgPair.depg)
440                     .append("|")
441                     .append(cgPair.dcgId)
442                     .append("|")
443                     .append(priority);
444         } else {
445             idb.append(cgPair.depg)
446                     .append("|")
447                     .append(cgPair.dcgId)
448                     .append("|")
449                     .append(cgPair.sepg)
450                     .append("|")
451                     .append(cgPair.scgId)
452                     .append("|")
453                     .append(priority);
454         }
455         return idb.toString();
456     }
457
458     private MatchBuilder createBaseMatch(Direction direction, CgPair cgPair, IpPrefix sIpPrefix, IpPrefix dIpPrefix) {
459         MatchBuilder baseMatch = new MatchBuilder();
460         if (direction.equals(Direction.In)) {
461             addNxRegMatch(baseMatch,
462                     RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
463                     RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
464                     RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
465                     RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
466             if (sIpPrefix != null) {
467                 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
468             }
469             if (dIpPrefix != null) {
470                 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
471             }
472         } else {
473             addNxRegMatch(baseMatch,
474                     RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
475                     RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
476                     RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
477                     RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
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>>>
506                 getActiveRulesBetweenEps(Policy policy, 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     @Immutable
529     private static class CgPair {
530
531         private final int sepg;
532         private final int depg;
533         private final int scgId;
534         private final int dcgId;
535         private final Set<IpPrefix> sIpPrefixes;
536         private final Set<IpPrefix> dIpPrefixes;
537
538         public CgPair(int sepg, int depg, int scgId, int dcgId, Set<IpPrefix> sIpPrefixes, Set<IpPrefix> dIpPrefixes) {
539             super();
540             this.sepg = sepg;
541             this.depg = depg;
542             this.scgId = scgId;
543             this.dcgId = dcgId;
544             this.sIpPrefixes = sIpPrefixes;
545             this.dIpPrefixes = dIpPrefixes;
546         }
547
548         @Override
549         public int hashCode() {
550             final int prime = 31;
551             int result = 1;
552             result = prime * result + ((dIpPrefixes == null) ? 0 : dIpPrefixes.hashCode());
553             result = prime * result + dcgId;
554             result = prime * result + depg;
555             result = prime * result + ((sIpPrefixes == null) ? 0 : sIpPrefixes.hashCode());
556             result = prime * result + scgId;
557             result = prime * result + sepg;
558             return result;
559         }
560
561         @Override
562         public boolean equals(Object obj) {
563             if (this == obj)
564                 return true;
565             if (obj == null)
566                 return false;
567             if (getClass() != obj.getClass())
568                 return false;
569             CgPair other = (CgPair) obj;
570             if (dIpPrefixes == null) {
571                 if (other.dIpPrefixes != null)
572                     return false;
573             } else if (!dIpPrefixes.equals(other.dIpPrefixes))
574                 return false;
575             if (dcgId != other.dcgId)
576                 return false;
577             if (sIpPrefixes == null) {
578                 if (other.sIpPrefixes != null)
579                     return false;
580             } else if (!sIpPrefixes.equals(other.sIpPrefixes))
581                 return false;
582             if (depg != other.depg)
583                 return false;
584             if (scgId != other.scgId)
585                 return false;
586             if (sepg != other.sepg)
587                 return false;
588             return true;
589         }
590     }
591
592     public class NetworkElements {
593         Endpoint src;
594         Endpoint dst;
595         NodeId nodeId;
596         EndpointFwdCtxOrdinals srcOrds;
597         EndpointFwdCtxOrdinals dstOrds;
598
599         public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception {
600             this.src=src;
601             this.dst=dst;
602             this.nodeId = nodeId;
603             this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src);
604             this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst);
605         }
606
607
608
609         public EndpointFwdCtxOrdinals getSrcOrds() {
610             return srcOrds;
611         }
612
613
614
615         public EndpointFwdCtxOrdinals getDstOrds() {
616             return dstOrds;
617         }
618
619
620         public Endpoint getSrc() {
621             return src;
622         }
623
624
625         public Endpoint getDst() {
626             return dst;
627         }
628
629
630         public NodeId getNodeId() {
631             return nodeId;
632         }
633
634
635     }
636 }