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