Implement SFC integration
[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.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.opendaylight.action.types.rev131112.action.list.ActionBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75 import com.google.common.collect.ComparisonChain;
76 import com.google.common.collect.Ordering;
77
78 /**
79  * Manage the table that enforces policy on the traffic. Traffic is denied
80  * unless specifically allowed by policy
81  */
82 public class PolicyEnforcer extends FlowTable {
83
84     protected static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
85
86     public static final short TABLE_ID = 3;
87
88     public PolicyEnforcer(OfContext ctx) {
89         super(ctx);
90     }
91
92     @Override
93     public short getTableId() {
94         return TABLE_ID;
95     }
96
97     @Override
98     public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
99
100         flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
101
102         NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class);
103         if (tunPort != null) {
104             flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
105         }
106
107         HashSet<CgPair> visitedPairs = new HashSet<>();
108
109         // Used for ARP flows
110         Set<Integer> fdIds = new HashSet<>();
111
112         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
113             for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
114                 Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
115                 for (EgKey dstEpgKey : peers) {
116                     for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey)) {
117                         // mEPG ordinals
118                         EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
119                                 policyInfo, srcEp);
120                         EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
121                                 policyInfo, dstEp);
122                         int dcgId = dstEpFwdCxtOrds.getCgId();
123                         int depgId = dstEpFwdCxtOrds.getEpgId();
124                         int scgId = srcEpFwdCxtOrds.getCgId();
125                         int sepgId = srcEpFwdCxtOrds.getEpgId();
126                         NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
127                         fdIds.add(srcEpFwdCxtOrds.getFdId());
128
129                         List<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp);
130                         ConditionGroup scg = policyInfo.getEgCondGroup(srcEpgKey, conds);
131                         conds = ctx.getEndpointManager().getCondsForEndpoint(dstEp);
132                         ConditionGroup dcg = policyInfo.getEgCondGroup(dstEpgKey, conds);
133
134                         Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
135                         List<RuleGroup> rgs = policy.getRules(dcg, scg);
136                         CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
137                         if (visitedPairs.contains(p))
138                             continue;
139                         visitedPairs.add(p);
140                         syncPolicy(flowMap, netElements, rgs, p);
141
142                         // Reverse
143                         policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
144                         rgs = policy.getRules(scg, dcg);
145                         p = new CgPair(sepgId, depgId, scgId, dcgId);
146                         if (visitedPairs.contains(p))
147                             continue;
148                         visitedPairs.add(p);
149                         syncPolicy(flowMap, netElements, rgs, p);
150                     }
151                 }
152             }
153         }
154
155         // Allow same EPG
156         // Set<Endpoint> visitedEps = new HashSet<>();
157         for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
158             // visitedEps.add(srcEp);
159             for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
160
161                 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
162                 EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
163                 IntraGroupPolicy igp = group.getIntraGroupPolicy();
164
165                 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
166                     for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
167                         // mEPG ordinals
168                         // if(visitedEps.contains(dstEp)) {
169                         // continue;
170                         // }
171                         // visitedEps.add(dstEp);
172                         EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
173                                 policyInfo, srcEp);
174                         EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
175                                 policyInfo, dstEp);
176                         int depgId = dstEpFwdCxtOrds.getEpgId();
177                         int sepgId = srcEpFwdCxtOrds.getEpgId();
178                         flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
179                         flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
180                     }
181                 }
182             }
183         }
184
185         // Write ARP flows per flood domain.
186         for (Integer fdId : fdIds) {
187             flowMap.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
188         }
189     }
190
191     private Flow createArpFlow(Integer fdId) {
192
193         Long etherType = FlowUtils.ARP;
194         // L2 Classifier so 20,000 for now
195         Integer priority = 20000;
196         FlowId flowid = new FlowId(new StringBuilder().append("arp")
197             .append("|")
198             .append(etherType)
199             .append("|")
200             .append(fdId)
201             .toString());
202
203         MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
204
205         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
206
207         Flow flow = base().setPriority(priority)
208             .setId(flowid)
209             .setMatch(mb.build())
210             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
211             .build();
212         return flow;
213     }
214
215     private Flow allowSameEpg(int sepgId, int depgId) {
216
217         FlowId flowId = new FlowId(new StringBuilder().append("intraallow|").append(sepgId).toString());
218         MatchBuilder mb = new MatchBuilder();
219         addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
220                 RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
221         FlowBuilder flow = base().setId(flowId)
222             .setMatch(mb.build())
223             .setPriority(65000)
224             .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
225         return flow.build();
226     }
227
228     private Flow allowFromTunnel(NodeConnectorId tunPort) {
229
230         FlowId flowId = new FlowId("tunnelallow");
231         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
232         addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
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
241     private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> rgs, CgPair p) {
242         int priority = 65000;
243         for (RuleGroup rg : rgs) {
244             TenantId tenantId = rg.getContractTenant().getId();
245             IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
246             for (Rule r : rg.getRules()) {
247                 syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority);
248                 syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority);
249
250                 priority -= 1;
251             }
252         }
253     }
254
255     /**
256      * Private internal class for ordering Actions in Rules. The order is
257      * determined first by the value of the order parameter, with the lower
258      * order actions being applied first; for Actions with either the same order
259      * or no order, ordering is lexicographical by name.
260      */
261     private static class ActionRefComparator implements Comparator<ActionRef> {
262
263         public static final ActionRefComparator INSTANCE = new ActionRefComparator();
264
265         @Override
266         public int compare(ActionRef arg0, ActionRef arg1) {
267             return ComparisonChain.start()
268                 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
269                 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
270                 .result();
271         }
272
273     }
274
275     private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
276             Direction direction, int priority) {
277         /*
278          * Create the ordered action list. The implicit action is "allow", and
279          * is therefore always in the list
280          *
281          * TODO: revisit implicit vs. default for "allow" TODO: look into
282          * incorporating operational policy for actions
283          */
284
285         // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
286         // referencing in sort
287         List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
288         if (rule.getActionRef() != null) {
289             /*
290              * Pre-sort by references using order, then name
291              */
292             List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
293             Collections.sort(arl, ActionRefComparator.INSTANCE);
294
295             for (ActionRef actionRule : arl) {
296                 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
297                 if (actionInstance == null) {
298                     // XXX TODO fail the match and raise an exception
299                     LOG.warn("Action instance {} not found", actionRule.getName().getValue());
300                     return;
301                 }
302                 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
303                 if (action == null) {
304                     // XXX TODO fail the match and raise an exception
305                     LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
306                     return;
307                 }
308
309                 Map<String, Object> params = new HashMap<>();
310                 if (actionInstance.getParameterValue() != null) {
311                     for (ParameterValue v : actionInstance.getParameterValue()) {
312                         if (v.getName() == null)
313                             continue;
314                         if (v.getIntValue() != null) {
315                             params.put(v.getName().getValue(), v.getIntValue());
316                         } else if (v.getStringValue() != null) {
317                             params.put(v.getName().getValue(), v.getStringValue());
318                         }
319                     }
320                 }
321                 /*
322                  * Convert the GBP Action to one or more OpenFlow Actions
323                  */
324                 actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements);
325             }
326         } else {
327             Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
328             actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
329         }
330
331         Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
332         Set<ClassifierDefinitionId> classifiers = new HashSet<>();
333         for (ClassifierRef cr : rule.getClassifierRef()) {
334             if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
335                     && !cr.getDirection().equals(direction)) {
336                 continue;
337             }
338
339             // XXX - TODO - implement connection tracking (requires openflow
340             // extension and data plane support - in 2.4. Will need to handle
341             // case where we are working with mix of nodes.
342
343             ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
344             if (ci == null) {
345                 // XXX TODO fail the match and raise an exception
346                 LOG.warn("Classifier instance {} not found", cr.getName().getValue());
347                 return;
348             }
349             Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
350             if (cfier == null) {
351                 // XXX TODO fail the match and raise an exception
352                 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
353                 return;
354             }
355             classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
356             for (ParameterValue v : ci.getParameterValue()) {
357
358                 if (v.getIntValue() != null) {
359                     paramsFromClassifier.put(v.getName().getValue(), v);
360                 } else if (v.getStringValue() != null) {
361                     paramsFromClassifier.put(v.getName().getValue(), v);
362                 } else if (v.getRangeValue() != null) {
363                     paramsFromClassifier.put(v.getName().getValue(), v);
364                 }
365             }
366         }
367         List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
368
369         for (Map<String, ParameterValue> params : derivedParamsByName) {
370             for (ClassifierDefinitionId clDefId : classifiers) {
371                 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
372                 StringBuilder idb = new StringBuilder();
373                 // XXX - TODO - implement connection tracking (requires openflow
374                 // extension and data plane support - in 2.4. Will need to handle
375                 // case where we are working with mix of nodes.
376
377                 MatchBuilder baseMatch = new MatchBuilder();
378                 if (direction.equals(Direction.In)) {
379                     idb.append(cgPair.sepg)
380                         .append("|")
381                         .append(cgPair.scgId)
382                         .append("|")
383                         .append(cgPair.depg)
384                         .append("|")
385                         .append(cgPair.dcgId)
386                         .append("|")
387                         .append(priority);
388                     addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
389                             RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
390                             RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
391                             RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
392                 } else {
393                     idb.append(cgPair.depg)
394                         .append("|")
395                         .append(cgPair.dcgId)
396                         .append("|")
397                         .append(cgPair.sepg)
398                         .append("|")
399                         .append(cgPair.scgId)
400                         .append("|")
401                         .append(priority);
402                     addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
403                             RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
404                             RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
405                             RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
406                 }
407
408                 List<MatchBuilder> matches = new ArrayList<>();
409                 matches.add(baseMatch);
410
411                 ClassificationResult result = classifier.updateMatch(matches, params);
412                 if (!result.isSuccessfull()) {
413                     // TODO consider different handling.
414                     throw new IllegalArgumentException(result.getErrorMessage());
415                 }
416                 String baseId = idb.toString();
417                 FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
418                 for (MatchBuilder match : result.getMatchBuilders()) {
419                     Match m = match.build();
420                     FlowId flowId = new FlowId(baseId + "|" + m.toString());
421                     flow.setMatch(m)
422                         .setId(flowId)
423                         .setPriority(Integer.valueOf(priority))
424                         .setInstructions(instructions(applyActionIns(actionBuilderList)));
425                     flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build());
426                 }
427             }
428         }
429     }
430
431     @Immutable
432     private static class CgPair {
433
434         private final int sepg;
435         private final int depg;
436         private final int scgId;
437         private final int dcgId;
438
439         public CgPair(int sepg, int depg, int scgId, int dcgId) {
440             super();
441             this.sepg = sepg;
442             this.depg = depg;
443             this.scgId = scgId;
444             this.dcgId = dcgId;
445         }
446
447         @Override
448         public int hashCode() {
449             final int prime = 31;
450             int result = 1;
451             result = prime * result + dcgId;
452             result = prime * result + depg;
453             result = prime * result + scgId;
454             result = prime * result + sepg;
455             return result;
456         }
457
458         @Override
459         public boolean equals(Object obj) {
460             if (this == obj)
461                 return true;
462             if (obj == null)
463                 return false;
464             if (getClass() != obj.getClass())
465                 return false;
466             CgPair other = (CgPair) obj;
467             if (dcgId != other.dcgId)
468                 return false;
469             if (depg != other.depg)
470                 return false;
471             if (scgId != other.scgId)
472                 return false;
473             if (sepg != other.sepg)
474                 return false;
475             return true;
476         }
477     }
478
479     public class NetworkElements {
480         Endpoint src;
481         Endpoint dst;
482         NodeId nodeId;
483         EndpointFwdCtxOrdinals srcOrds;
484         EndpointFwdCtxOrdinals dstOrds;
485
486         public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception {
487             this.src=src;
488             this.dst=dst;
489             this.nodeId = nodeId;
490             this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src);
491             this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst);
492         }
493
494
495
496         public EndpointFwdCtxOrdinals getSrcOrds() {
497             return srcOrds;
498         }
499
500
501
502         public EndpointFwdCtxOrdinals getDstOrds() {
503             return dstOrds;
504         }
505
506
507         public Endpoint getSrc() {
508             return src;
509         }
510
511
512         public Endpoint getDst() {
513             return dst;
514         }
515
516
517         public NodeId getNodeId() {
518             return nodeId;
519         }
520
521
522     }
523 }