2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.ArrayListMultimap;
13 import com.google.common.collect.ComparisonChain;
14 import com.google.common.collect.ListMultimap;
15 import com.google.common.collect.Ordering;
16 import com.google.common.collect.Table.Cell;
17 import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
18 import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
19 import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
20 import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
21 import org.opendaylight.groupbasedpolicy.dto.EgKey;
22 import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint;
23 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
24 import org.opendaylight.groupbasedpolicy.dto.Policy;
25 import org.opendaylight.groupbasedpolicy.dto.RuleGroup;
26 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
27 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
28 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
29 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
30 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
31 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
32 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
33 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
34 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
35 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
37 import org.opendaylight.groupbasedpolicy.util.TenantUtils;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup.IntraGroupPolicy;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
74 import javax.annotation.concurrent.Immutable;
75 import java.util.ArrayList;
76 import java.util.Collections;
77 import java.util.Comparator;
78 import java.util.HashMap;
79 import java.util.HashSet;
80 import java.util.List;
84 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
87 * Manage the table that enforces policy on the traffic. Traffic is denied
88 * unless specifically allowed by policy
90 public class PolicyEnforcer extends FlowTable {
92 private static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
93 public static short TABLE_ID;
94 private static boolean isReversedPolicy;
95 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoEgressNatInstruction;
96 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoExternalInstruction;
97 private HashSet<PolicyPair> visitedPairs = new HashSet<>();
98 private HashSet<PolicyPair> visitedReversePairs = new HashSet<>();
99 private List<Rule> reversedActiveRules = new ArrayList<>();
100 private ListMultimap<EgKey, EgKey> resolvedEpgPairs = ArrayListMultimap.create();
101 private boolean directPathFlowsCreated = false;
102 private boolean reversePathFlowsCreated = false;
104 public PolicyEnforcer(OfContext ctx, short tableId) {
107 isReversedPolicy = false;
108 gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
109 gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER());
112 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
113 return gotoEgressNatInstruction;
116 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
117 return gotoExternalInstruction;
121 public short getTableId() {
126 public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
128 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
130 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
131 if (tunPort != null) {
132 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
135 visitedPairs = new HashSet<>();
136 reversedActiveRules = new ArrayList<>();
137 visitedReversePairs = new HashSet<>();
138 resolvedEpgPairs = ArrayListMultimap.create();
140 // Used for ARP flows
141 Set<Integer> fdIds = new HashSet<>();
143 for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
144 for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
145 Set<EgKey> peers = ctx.getCurrentPolicy().getPeers(sourceEpgKey);
146 for (EgKey destinationEpgKey : peers) {
148 Set<Endpoint> destinationEndpoints = new HashSet<>();
149 destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(destinationEpgKey));
150 destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(destinationEpgKey));
151 for (Endpoint destinationEp : destinationEndpoints) {
153 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
154 if (srcEpFwdCxtOrdinals == null) {
155 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", sourceEp);
159 EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEp);
160 if (dstEpFwdCxtOrdinals == null) {
161 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEp);
165 fdIds.add(srcEpFwdCxtOrdinals.getFdId());
166 NetworkElements netElements = new NetworkElements(sourceEp, destinationEp, sourceEpgKey,
167 destinationEpgKey, nodeId, ctx);
169 // Get policy in both directions
170 Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destinationEpgKey, sourceEpgKey);
171 Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpgKey, destinationEpgKey);
172 reversedActiveRules = getRules(getActiveRulesBetweenEps(destinationEpgPolicy, sourceEp, destinationEp));
174 // Resolve flows in both directions if possible according to policy. Get back status of resolution
175 PathStatus status = resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy);
177 // When source Epg policy creates no flows, destination Epg policy has to be resolved
178 if (status.equals(PathStatus.none)) {
179 resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, false);
181 // When source Epg policy creates flows only in one direction, the other direction has to be
182 // created here. Is essential to revert directions to prevent flow overriding and incorrect nsp
184 else if (status.equals(PathStatus.partial)) {
185 resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, true);
193 allowSameEpg(nodeId, ofWriter);
195 // Write ARP flows per flood domain
196 for (Integer fdId : fdIds) {
197 ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
201 private PathStatus resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy) {
202 isReversedPolicy = false;
203 directPathFlowsCreated = false;
204 reversePathFlowsCreated = false;
206 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
207 directPolicy, netElements.getDstEp(), netElements.getSrcEp())) {
208 Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
210 Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
212 PolicyPair policyPair = new PolicyPair(netElements.getDstEpOrdinals().getEpgId(), netElements.getSrcEpOrdinals().getEpgId(),
213 netElements.getDstEpOrdinals().getCgId(), netElements.getSrcEpOrdinals().getCgId(), dIpPrefixes, sIpPrefixes,
214 netElements.getDstNodeId(), netElements.getSrcNodeId());
215 if (visitedPairs.contains(policyPair)) {
216 LOG.trace("PolicyEnforcer: Already visited PolicyPair {}, endpoints {} {} skipped",
217 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
220 LOG.trace("PolicyEnforcer: Visiting PolicyPair {} endpoints {} {}", policyPair,
221 netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
222 visitedPairs.add(policyPair);
225 int priority = 65000;
226 for (RuleGroup rg : activeRulesByConstraints.getValue()) {
227 TenantId tenantId = rg.getContractTenant().getId();
228 IndexedTenant tenant = ctx.getTenant(tenantId);
229 for (Rule rule : rg.getRules()) {
231 // Find all rules in the same traffic direction
232 List<Rule> sameDirectionRules = findRulesInSameDirection(rule, reversedActiveRules);
233 if (sameDirectionRules.isEmpty()) {
234 sameDirectionRules.add(rule);
236 sameDirectionRules = Ordering.from(TenantUtils.RULE_COMPARATOR)
237 .immutableSortedCopy(sameDirectionRules);
239 // Create flows for every pair of rules
240 for (Rule oppositeRule : sameDirectionRules) {
242 // Evaluate which rule has more specific matches
243 Rule ruleWithMatches = findRuleWithSpecificMatches(rule, oppositeRule, tenant);
244 Rule ruleWithActions = mergeRuleActions(rule, oppositeRule, tenant);
245 if (ruleWithMatches == null) {
246 LOG.trace("No matches found for pair of rules {}, {}", rule, oppositeRule);
249 if (ruleWithActions == null) {
250 LOG.trace("No actions found for pair of rules {}, {}", rule, oppositeRule);
254 // Preserve original rule direction
255 Set<Direction> directions = getRuleDirections(rule);
257 for(Direction direction : directions) {
259 // Create list of matches/actions. Also creates chain flows when specific action requires it
260 List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant,
262 List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant,
265 List<ActionBuilder> actions = createActions(ofWriter, netElements, direction,
266 policyPair, tenant, ruleWithActions, false);
269 createFlows(inMatches, actions, netElements, ofWriter, priority);
270 createFlows(outMatches, actions, netElements, ofWriter, priority);
274 // Keep info about what direction has flows already created
275 if (direction.equals(Direction.In)) {
276 directPathFlowsCreated = true;
278 if (direction.equals(Direction.Out)) {
279 reversePathFlowsCreated = true;
282 // Fully resolved Ep groups are saved to prevent duplicates
283 if (directPathFlowsCreated && reversePathFlowsCreated) {
284 LOG.trace("Epg pair added: {}, {} ", netElements.getSrcEpg(), netElements.getDstEpg());
285 resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
293 // Returns appropriate result of resolving
294 if (directPathFlowsCreated && reversePathFlowsCreated) {
295 return PathStatus.both;
296 } else if ((!directPathFlowsCreated && reversePathFlowsCreated) || (directPathFlowsCreated && !reversePathFlowsCreated)) {
297 return PathStatus.partial;
299 return PathStatus.none;
303 private Set<Direction> getRuleDirections(Rule ruleWithMatches) {
304 Set<Direction> directions = new HashSet<>();
305 for (ClassifierRef classifierRef : ruleWithMatches.getClassifierRef()) {
306 if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.In) {
307 directions.add(classifierRef.getDirection());
309 if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.Out) {
310 directions.add(classifierRef.getDirection());
313 if (directions.isEmpty()) {
314 directions.add(Direction.Bidirectional);
319 private Rule mergeRuleActions(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
320 if (oppositeRule.equals(rule)) {
324 Action ruleAction = null;
325 Action oppositeRuleAction = null;
327 // For now, only allow action and chain action is supported
328 for (ActionRef actionRef : rule.getActionRef()) {
329 ActionInstance actionInstance = tenant.getAction(actionRef.getName());
330 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
331 ruleAction = new AllowAction();
333 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
334 ruleAction = new ChainAction();
337 for (ActionRef actionRef : oppositeRule.getActionRef()) {
338 ActionInstance actionInstance = tenant.getAction(actionRef.getName());
339 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
340 oppositeRuleAction = new AllowAction();
342 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
343 oppositeRuleAction = new ChainAction();
347 if (ruleAction == null && oppositeRuleAction == null) {
349 } else if (ruleAction != null && ruleAction.getClass().equals(AllowAction.class)) {
351 } else if (oppositeRuleAction != null && oppositeRuleAction.getClass().equals(AllowAction.class)) {
354 // TODO both rules have chain action - add support for more different chain actions. This works for now
359 private Rule findRuleWithSpecificMatches(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
360 if (oppositeRule.equals(rule)) {
364 // TODO check all classifierRefs
365 ClassifierRef ruleClassifierRef = rule.getClassifierRef().get(0);
366 ClassifierRef oppositeRuleClassifierRef = oppositeRule.getClassifierRef().get(0);
368 ClassifierInstance ruleClassifierInstance = tenant.getClassifier(ruleClassifierRef.getInstanceName());
369 ClassifierInstance oppositeRuleClassifierInstance = tenant.getClassifier(oppositeRuleClassifierRef.getInstanceName());
371 if (ruleClassifierInstance == null) {
372 LOG.trace("Classifier instance not found, ClassifierRef name: {} ", ruleClassifierRef.getInstanceName());
375 if (oppositeRuleClassifierInstance == null) {
376 LOG.trace("Opposite classifier instance not found, ClassifierRef name: {} ", oppositeRuleClassifierRef.getInstanceName());
380 // Check ethertype. Values must be equal
381 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
382 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
383 if ((ruleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
384 && oppositeRuleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)) {
385 if (!ruleParameter.getIntValue().equals(oppositeRuleParameter.getIntValue())) {
386 LOG.trace("Ethertype values are not equal, rule: {}, opposite rule: {} ", rule, oppositeRule);
392 // Check proto if exists. Values must be equal or missing
393 ParameterValue ruleProtoParameter = null;
394 ParameterValue oppositeRuleProtoParameter = null;
395 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
396 if (ruleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
397 ruleProtoParameter = ruleParameter;
400 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
401 if (oppositeRuleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
402 oppositeRuleProtoParameter = oppositeRuleParameter;
406 if (ruleProtoParameter == null || ruleProtoParameter.getIntValue() == null) {
408 } else if (oppositeRuleProtoParameter == null || oppositeRuleProtoParameter.getIntValue() == null) {
410 } else if (!ruleProtoParameter.getIntValue().equals(oppositeRuleProtoParameter.getIntValue())) {
411 LOG.trace("Proto parameters are not equal, rule parameters: {}, opposite rule parameters {} ",
412 ruleProtoParameter, oppositeRuleProtoParameter);
417 // TODO add support for port ranges
418 ParameterValue ruleL4Src = null;
419 ParameterValue oppositeRuleL4Src = null;
420 ParameterValue ruleL4Dst = null;
421 ParameterValue oppositeRuleL4Dst = null;
423 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
424 if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
425 ruleL4Src = ruleParameter;
427 if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
428 ruleL4Dst = ruleParameter;
431 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
432 if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
433 oppositeRuleL4Src = oppositeRuleParameter;
435 if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
436 oppositeRuleL4Dst = oppositeRuleParameter;
440 if (ruleL4Src == null && ruleL4Dst == null && oppositeRuleL4Src == null && oppositeRuleL4Dst == null) {
445 if (ruleL4Src == null && oppositeRuleL4Src != null) {
448 if (ruleL4Src != null && oppositeRuleL4Src == null) {
451 if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
452 && ruleL4Src.equals(oppositeRuleL4Src)) {
455 if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
456 && !ruleL4Src.equals(oppositeRuleL4Src)) {
461 if (ruleL4Dst == null && oppositeRuleL4Dst != null) {
464 if (ruleL4Dst != null && oppositeRuleL4Dst == null) {
467 if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
468 && ruleL4Dst.equals(oppositeRuleL4Dst)) {
471 if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
472 && !ruleL4Dst.equals(oppositeRuleL4Dst)) {
479 private void resolveDestinationEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy reversedPolicy,
480 boolean isReverted) {
481 isReversedPolicy = true;
482 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
483 reversedPolicy, netElements.getSrcEp(), netElements.getDstEp())) {
484 Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
486 Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
488 PolicyPair policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getEpgId(),
489 netElements.getSrcEpOrdinals().getCgId(), netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
490 netElements.getSrcNodeId(), netElements.getDstNodeId());
491 if (visitedReversePairs.contains(policyPair)) {
493 "PolicyEnforcer: Reverse: Already visited PolicyPair {}, endpoints {} {} skipped",
494 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
497 LOG.trace("PolicyEnforcer: Reverse: Visiting: PolicyPair {} via endpoints {} {}",
498 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
499 visitedReversePairs.add(policyPair);
502 int priority = 65000;
503 for (RuleGroup rg : activeRulesByConstraints.getValue()) {
504 TenantId tenantId = rg.getContractTenant().getId();
505 IndexedTenant tenant = ctx.getTenant(tenantId);
506 for (Rule rule : rg.getRules()) {
508 Set<Direction> directions = getRuleDirections(rule);
509 if (directions.isEmpty()) {
513 for(Direction direction : directions) {
515 // When specific direction flows exists, do not create them again
516 if (direction.equals(Direction.In) && reversePathFlowsCreated) {
519 if (direction.equals(Direction.Out) && directPathFlowsCreated) {
523 List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant, rule);
524 List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant, rule);
526 // In case chain action is called here, it has to know that this is reversed policy to set tunnel
528 List<ActionBuilder> inActions = createActions(ofWriter, netElements, Direction.In, policyPair, tenant,
530 List<ActionBuilder> outActions = createActions(ofWriter, netElements, Direction.Out, policyPair, tenant,
533 createFlows(inMatches, inActions, netElements, ofWriter, priority);
534 createFlows(outMatches, outActions, netElements, ofWriter, priority);
536 if (direction.equals(Direction.In)) {
537 reversePathFlowsCreated = true;
539 if (direction.equals(Direction.Out)) {
540 directPathFlowsCreated = true;
545 if (directPathFlowsCreated && reversePathFlowsCreated) {
546 resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
554 private void allowSameEpg(NodeId nodeId, OfWriter ofWriter) throws Exception {
555 for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
556 for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
558 IndexedTenant tenant = ctx.getTenant(sourceEpgKey.getTenantId());
559 if (tenant != null) {
560 EndpointGroup group = tenant.getEndpointGroup(sourceEpgKey.getEgId());
562 LOG.debug("EPG {} does not exit and is used in EP {}", sourceEpgKey, sourceEp.getKey());
565 IntraGroupPolicy igp = group.getIntraGroupPolicy();
567 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
568 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(sourceEpgKey)) {
569 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
570 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
571 if (srcEpFwdCxtOrdinals == null) {
572 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
576 EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
577 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
578 if (dstEpFwdCxtOrdinals == null) {
579 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
583 int destinationEpgId = dstEpFwdCxtOrdinals.getEpgId();
584 int sourceEpgId = srcEpFwdCxtOrdinals.getEpgId();
585 ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(sourceEpgId, destinationEpgId));
586 ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(destinationEpgId, sourceEpgId));
594 // Return list of all rules with opposite direction
595 private List<Rule> findRulesInSameDirection(Rule ruleToResolve, List<Rule> reversedRules) {
596 List<Rule> sameDirectionRules = new ArrayList<>();
597 for (Rule ruleToCompare : reversedRules) {
598 for (ClassifierRef classifierRefToCompare : ruleToCompare.getClassifierRef()) {
599 for (ClassifierRef classifierRefToResolve : ruleToResolve.getClassifierRef()) {
600 if (isDirectionOpposite(classifierRefToCompare.getDirection(), classifierRefToResolve.getDirection())) {
601 sameDirectionRules.add(ruleToCompare);
606 return sameDirectionRules;
609 private boolean isDirectionOpposite(Direction one, Direction two) {
610 return ((one.equals(Direction.In) && two.equals(Direction.Out))
611 || (one.equals(Direction.Out) && two.equals(Direction.In)));
614 private List<Rule> getRules(List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules) {
615 List<Rule> rules = new ArrayList<>();
616 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRule : activeRules) {
617 for (RuleGroup ruleGroup : activeRule.getValue()) {
618 for (Rule rule : ruleGroup.getRules()) {
626 private Flow createArpFlow(Integer fdId) {
628 Long etherType = FlowUtils.ARP;
629 // L2 Classifier so 20,000 for now
630 Integer priority = 20000;
632 MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
634 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
636 Match match = mb.build();
637 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
638 return base().setPriority(priority)
641 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
645 private Flow allowSameEpg(int sourceEpgId, int destinationEpgId) {
647 MatchBuilder mb = new MatchBuilder();
648 addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) sourceEpgId),
649 RegMatch.of(NxmNxReg2.class, (long) destinationEpgId));
650 Match match = mb.build();
651 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
652 FlowBuilder flow = base().setId(flowId)
655 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
659 private Flow allowFromTunnel(NodeConnectorId tunPort) {
661 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
662 addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
663 Match match = mb.build();
664 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
665 FlowBuilder flow = base().setId(flowId)
668 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
673 private List<MatchBuilder> createMatches(Direction direction, PolicyPair policyPair, IndexedTenant contractTenant,
675 Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
676 Set<ClassifierDefinitionId> classifiers = new HashSet<>();
677 for (ClassifierRef cr : rule.getClassifierRef()) {
679 if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
680 && !cr.getDirection().equals(direction)) {
684 // XXX - TODO - implement connection tracking (requires openflow
685 // extension and data plane support - in 2.4. Will need to handle
686 // case where we are working with mix of nodes.
688 ClassifierInstance ci = contractTenant.getClassifier(cr.getInstanceName());
690 // XXX TODO fail the match and raise an exception
691 LOG.warn("Classifier instance {} not found", cr.getInstanceName().getValue());
694 Classifier classifier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
695 if (classifier == null) {
696 // XXX TODO fail the match and raise an exception
697 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
700 classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
701 for (ParameterValue v : ci.getParameterValue()) {
702 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
703 if (v.getIntValue() != null || v.getStringValue() != null || v.getRangeValue() != null) {
704 paramsFromClassifier.put(v.getName().getValue(), v);
707 if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
708 throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
709 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
714 if (classifiers.isEmpty()) {
717 List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
718 List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
719 for (Map<String, ParameterValue> params : derivedParamsByName) {
720 List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
721 if (policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
722 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, null));
723 } else if (!policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
724 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
725 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, null));
727 } else if (policyPair.consumerEicIpPrefixes.isEmpty() && !policyPair.providerEicIpPrefixes.isEmpty()) {
728 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
729 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, dIpPrefix));
732 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
733 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
734 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, dIpPrefix));
738 for (ClassifierDefinitionId clDefId : classifiers) {
739 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
740 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
741 if (!result.isSuccessfull()) {
742 // TODO consider different handling.
743 throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName()
744 + ".\nCause: " + result.getErrorMessage());
746 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
748 flowMatchBuilders.addAll(matchBuildersToResolve);
750 return flowMatchBuilders;
753 private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction, PolicyPair policyPair,
754 IndexedTenant contractTenant, Rule rule, boolean isReversedDirection) {
755 List<ActionBuilder> actionBuilderList = new ArrayList<>();
756 if (rule.getActionRef() != null) {
758 // Pre-sort by references using order, then name
759 List<ActionRef> actionRefList = new ArrayList<>(rule.getActionRef());
760 Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
762 for (ActionRef actionRule : actionRefList) {
763 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
764 if (actionInstance == null) {
765 // XXX TODO fail the match and raise an exception
766 LOG.warn("Action instance {} not found", actionRule.getName().getValue());
769 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
770 if (action == null) {
771 // XXX TODO fail the match and raise an exception
772 LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
776 Map<String, Object> params = new HashMap<>();
777 if (actionInstance.getParameterValue() != null) {
778 for (ParameterValue v : actionInstance.getParameterValue()) {
779 if (v.getName() == null)
781 if (v.getIntValue() != null) {
782 params.put(v.getName().getValue(), v.getIntValue());
783 } else if (v.getStringValue() != null) {
784 params.put(v.getName().getValue(), v.getStringValue());
788 if (isReversedDirection) {
789 direction = reverse(direction);
792 // Convert the GBP Action to one or more OpenFlow Actions
793 if (!(actionRefList.indexOf(actionRule) == (actionRefList.size() - 1)
794 && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId())))) {
795 actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(), netElements,
796 policyPair, ofWriter, ctx, direction);
801 return actionBuilderList;
804 private Direction reverse(Direction direction) {
805 if (direction.equals(Direction.In)) {
806 return Direction.Out;
808 else if(direction.equals(Direction.Out)) {
812 return Direction.Bidirectional;
816 private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList, NetworkElements netElements,
817 OfWriter ofWriter, int priority) {
818 FlowBuilder flow = base().setPriority(priority);
819 if(flowMatchBuilders == null) {
822 for (MatchBuilder mb : flowMatchBuilders) {
823 Match match = mb.build();
824 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "cg", match);
825 flow.setMatch(match).setId(flowId).setPriority(priority);
827 // If destination is External, the last Action ALLOW must be changed to goto
828 // NAT/External table.
829 // If actionBuilderList is empty (we removed the last Allow) then go straight to
830 // ExternalMapper table.
832 if (ctx.getEndpointManager().isExternal(netElements.getDstEp())) {
833 flow.setInstructions(instructions(getGotoEgressNatInstruction()));
834 } else if (actionBuilderList == null) {
835 //TODO - analyse, what happen for unknown action, SFC, etc.
836 LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
838 } else if (actionBuilderList.isEmpty()) {
839 flow.setInstructions(instructions(getGotoExternalInstruction()));
841 flow.setInstructions(instructions(applyActionIns(actionBuilderList), getGotoExternalInstruction()));
843 ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
847 private MatchBuilder createBaseMatch(Direction direction, PolicyPair policyPair, IpPrefix sIpPrefix,
848 IpPrefix dIpPrefix) {
849 MatchBuilder baseMatch = new MatchBuilder();
850 if (direction.equals(Direction.In)) {
851 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.consumerEpgId),
852 RegMatch.of(NxmNxReg1.class, (long) policyPair.consumerCondGrpId),
853 RegMatch.of(NxmNxReg2.class, (long) policyPair.providerEpgId),
854 RegMatch.of(NxmNxReg3.class, (long) policyPair.providerCondGrpId));
855 if (sIpPrefix != null) {
856 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
858 if (dIpPrefix != null) {
859 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
862 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.providerEpgId),
863 RegMatch.of(NxmNxReg1.class, (long) policyPair.providerCondGrpId),
864 RegMatch.of(NxmNxReg2.class, (long) policyPair.consumerEpgId),
865 RegMatch.of(NxmNxReg3.class, (long) policyPair.consumerCondGrpId));
866 if (sIpPrefix != null) {
867 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
869 if (dIpPrefix != null) {
870 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
876 private Layer3Match createLayer3Match(IpPrefix ipPrefix, boolean isSrc) {
877 if (ipPrefix.getIpv4Prefix() != null) {
879 return new Ipv4MatchBuilder().setIpv4Source(ipPrefix.getIpv4Prefix()).build();
881 return new Ipv4MatchBuilder().setIpv4Destination(ipPrefix.getIpv4Prefix()).build();
885 return new Ipv6MatchBuilder().setIpv6Source(ipPrefix.getIpv6Prefix()).build();
887 return new Ipv6MatchBuilder().setIpv6Destination(ipPrefix.getIpv6Prefix()).build();
892 // TODO: move to a common utils for all renderers
893 private List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
894 Endpoint consEp, Endpoint provEp) {
895 List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
896 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
897 EndpointConstraint consEpConstraint = cell.getRowKey();
898 EndpointConstraint provEpConstraint = cell.getColumnKey();
899 if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
900 rulesWithEpConstraints.add(cell);
903 return rulesWithEpConstraints;
906 private boolean epMatchesConstraint(Endpoint ep, EndpointConstraint constraint) {
907 List<ConditionName> epConditions = Collections.emptyList();
908 if (ep.getCondition() != null) {
909 epConditions = ep.getCondition();
911 return constraint.getConditionSet().matches(epConditions);
914 private enum PathStatus { both, partial, none }
916 public static boolean checkPolicyOrientation() {
917 return isReversedPolicy;
921 * Private internal class for ordering Actions in Rules. The order is
922 * determined first by the value of the order parameter, with the lower
923 * order actions being applied first; for Actions with either the same order
924 * or no order, ordering is lexicographical by name.
926 private static class ActionRefComparator implements Comparator<ActionRef> {
928 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
931 public int compare(ActionRef arg0, ActionRef arg1) {
932 return ComparisonChain.start()
933 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
934 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
941 public static class PolicyPair {
943 private final int consumerEpgId;
944 private final int providerEpgId;
945 private final int consumerCondGrpId;
946 private final int providerCondGrpId;
947 private final Set<IpPrefix> consumerEicIpPrefixes;
948 private final Set<IpPrefix> providerEicIpPrefixes;
949 private final NodeId consumerEpNodeId;
950 private final NodeId providerEpNodeId;
952 public PolicyPair(int consumerEpgId, int providerEpgId, int consumerCondGrpId, int providerCondGrpId,
953 Set<IpPrefix> consumerEicIpPrefixes, Set<IpPrefix> providerEicIpPrefixes, NodeId consumerEpNodeId, NodeId providerEpNodeId) {
955 this.consumerEpgId = consumerEpgId;
956 this.providerEpgId = providerEpgId;
957 this.consumerCondGrpId = consumerCondGrpId;
958 this.providerCondGrpId = providerCondGrpId;
959 this.consumerEicIpPrefixes = consumerEicIpPrefixes;
960 this.providerEicIpPrefixes = providerEicIpPrefixes;
961 this.consumerEpNodeId = consumerEpNodeId;
962 this.providerEpNodeId = providerEpNodeId;
965 public int getConsumerEpgId() {
966 return consumerEpgId;
969 public int getProviderEpgId() {
970 return providerEpgId;
973 public NodeId getConsumerEpNodeId() {
974 return consumerEpNodeId;
977 public NodeId getProviderEpNodeId() {
978 return providerEpNodeId;
982 public int hashCode() {
983 final int prime = 31;
985 result = prime * result + ((providerEicIpPrefixes == null) ? 0 : providerEicIpPrefixes.hashCode());
986 result = prime * result + providerCondGrpId;
987 result = prime * result + providerEpgId;
988 result = prime * result + ((consumerEicIpPrefixes == null) ? 0 : consumerEicIpPrefixes.hashCode());
989 result = prime * result + consumerCondGrpId;
990 result = prime * result + consumerEpgId;
991 result = prime * result + ((consumerEpNodeId == null) ? 0 : consumerEpNodeId.hashCode());
992 result = prime * result + ((providerEpNodeId == null) ? 0 : providerEpNodeId.hashCode());
998 public boolean equals(Object obj) {
1003 if (getClass() != obj.getClass())
1005 PolicyPair other = (PolicyPair) obj;
1006 if (providerEicIpPrefixes == null) {
1007 if (other.providerEicIpPrefixes != null) {
1010 } else if (!providerEicIpPrefixes.equals(other.providerEicIpPrefixes)) {
1013 if (consumerEicIpPrefixes == null) {
1014 if (other.consumerEicIpPrefixes != null) {
1017 } else if (!consumerEicIpPrefixes.equals(other.consumerEicIpPrefixes)) {
1020 if (consumerEpNodeId == null) {
1021 if (other.consumerEpNodeId != null) {
1024 } else if (!consumerEpNodeId.getValue().equals(other.consumerEpNodeId.getValue())) {
1027 if (providerEpNodeId == null) {
1028 if (other.providerEpNodeId != null) {
1031 } else if (!providerEpNodeId.getValue().equals(other.providerEpNodeId.getValue())) {
1034 return (providerCondGrpId == other.providerCondGrpId)
1035 && (providerEpgId == other.providerEpgId)
1036 && (consumerCondGrpId == other.consumerCondGrpId)
1037 && (consumerEpgId == other.consumerEpgId);
1042 public String toString() {
1043 return "consumerEPG: " + consumerEpgId +
1044 "consumerCG: " + consumerCondGrpId +
1045 "providerEPG: " + providerEpgId +
1046 "providerCG: " + providerCondGrpId +
1047 "consumerEpNodeId: " + consumerEpNodeId +
1048 "providerEpNodeId: " + providerEpNodeId +
1049 "consumerEicIpPrefixes: " + consumerEicIpPrefixes +
1050 "providerEicIpPrefixes: " + providerEicIpPrefixes;
1054 public class NetworkElements {
1056 private final Endpoint srcEp;
1057 private final Endpoint dstEp;
1058 private final EgKey srcEpg;
1059 private final EgKey dstEpg;
1060 private NodeId srcNodeId;
1061 private NodeId dstNodeId;
1062 private final NodeId localNodeId;
1063 private EndpointFwdCtxOrdinals srcEpOrdinals;
1064 private EndpointFwdCtxOrdinals dstEpOrdinals;
1066 public NetworkElements(Endpoint srcEp, Endpoint dstEp, EgKey srcEpg, EgKey dstEpg, NodeId nodeId, OfContext ctx) throws Exception {
1067 Preconditions.checkArgument(srcEp.getAugmentation(OfOverlayContext.class) != null);
1068 Preconditions.checkArgument(dstEp.getAugmentation(OfOverlayContext.class) != null);
1072 this.srcEpg = srcEpg;
1073 this.dstEpg = dstEpg;
1074 this.localNodeId = nodeId;
1075 this.srcEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);
1076 if (this.srcEpOrdinals == null) {
1077 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
1080 this.dstEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
1081 if (this.dstEpOrdinals == null) {
1082 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
1085 this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();
1086 this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();
1090 public Endpoint getSrcEp() {
1095 public Endpoint getDstEp() {
1099 public EgKey getSrcEpg() {
1103 public EgKey getDstEpg() {
1107 public NodeId getSrcNodeId() {
1112 public NodeId getDstNodeId() {
1117 public NodeId getLocalNodeId() {
1122 public EndpointFwdCtxOrdinals getSrcEpOrdinals() {
1123 return srcEpOrdinals;
1127 public EndpointFwdCtxOrdinals getDstEpOrdinals() {
1128 return dstEpOrdinals;