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 static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
26 import javax.annotation.concurrent.Immutable;
28 import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
29 import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
30 import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
31 import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
32 import org.opendaylight.groupbasedpolicy.dto.EgKey;
33 import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint;
34 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
35 import org.opendaylight.groupbasedpolicy.dto.Policy;
36 import org.opendaylight.groupbasedpolicy.dto.RuleGroup;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
38 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
39 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
40 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
41 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
42 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
43 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
44 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
45 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
46 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
47 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
48 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
49 import org.opendaylight.groupbasedpolicy.util.TenantUtils;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup.IntraGroupPolicy;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
87 import com.google.common.collect.ArrayListMultimap;
88 import com.google.common.collect.ComparisonChain;
89 import com.google.common.collect.ListMultimap;
90 import com.google.common.collect.Ordering;
91 import com.google.common.collect.Table.Cell;
94 * Manage the table that enforces policy on the traffic. Traffic is denied
95 * unless specifically allowed by policy
97 public class PolicyEnforcer extends FlowTable {
99 private static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
100 public static short TABLE_ID;
101 private static boolean isReversedPolicy;
102 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoEgressNatInstruction;
103 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoExternalInstruction;
104 private HashSet<PolicyPair> visitedPairs = new HashSet<>();
105 private HashSet<PolicyPair> visitedReversePairs = new HashSet<>();
106 private List<Rule> reversedActiveRules = new ArrayList<>();
107 private ListMultimap<EgKey, EgKey> resolvedEpgPairs = ArrayListMultimap.create();
108 private boolean directPathFlowsCreated = false;
109 private boolean reversePathFlowsCreated = false;
111 public PolicyEnforcer(OfContext ctx, short tableId) {
114 isReversedPolicy = false;
115 gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
116 gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER());
119 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
120 return gotoEgressNatInstruction;
123 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
124 return gotoExternalInstruction;
128 public short getTableId() {
133 public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
135 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
137 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
138 if (tunPort != null) {
139 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
142 visitedPairs = new HashSet<>();
143 reversedActiveRules = new ArrayList<>();
144 visitedReversePairs = new HashSet<>();
145 resolvedEpgPairs = ArrayListMultimap.create();
147 // Used for ARP flows
148 Set<Integer> fdIds = new HashSet<>();
150 for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
151 for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
152 Set<EgKey> peers = ctx.getCurrentPolicy().getPeers(sourceEpgKey);
153 for (EgKey destinationEpgKey : peers) {
155 Set<Endpoint> destinationEndpoints = new HashSet<>();
156 destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(destinationEpgKey));
157 destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(destinationEpgKey));
158 for (Endpoint destinationEp : destinationEndpoints) {
160 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
161 if (srcEpFwdCxtOrdinals == null) {
162 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", sourceEp);
166 EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEp);
167 if (dstEpFwdCxtOrdinals == null) {
168 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEp);
172 fdIds.add(srcEpFwdCxtOrdinals.getFdId());
173 NetworkElements netElements = new NetworkElements(sourceEp, destinationEp, sourceEpgKey,
174 destinationEpgKey, nodeId, ctx);
176 // Get policy in both directions
177 Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destinationEpgKey, sourceEpgKey);
178 Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpgKey, destinationEpgKey);
179 reversedActiveRules = getRules(getActiveRulesBetweenEps(destinationEpgPolicy, sourceEp, destinationEp));
181 // Resolve flows in both directions if possible according to policy. Get back status of resolution
182 PathStatus status = resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy);
184 // When source Epg policy creates no flows, destination Epg policy has to be resolved
185 if (status.equals(PathStatus.none)) {
186 resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, false);
188 // When source Epg policy creates flows only in one direction, the other direction has to be
189 // created here. Is essential to revert directions to prevent flow overriding and incorrect nsp
191 else if (status.equals(PathStatus.partial)) {
192 resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, true);
200 allowSameEpg(nodeId, ofWriter);
202 // Write ARP flows per flood domain
203 for (Integer fdId : fdIds) {
204 ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
208 private PathStatus resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy) {
209 isReversedPolicy = false;
210 directPathFlowsCreated = false;
211 reversePathFlowsCreated = false;
213 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
214 directPolicy, netElements.getDstEp(), netElements.getSrcEp())) {
215 Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
217 Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
219 PolicyPair policyPair = new PolicyPair(netElements.getDstEpOrdinals().getEpgId(), netElements.getSrcEpOrdinals().getEpgId(),
220 netElements.getDstEpOrdinals().getCgId(), netElements.getSrcEpOrdinals().getCgId(), dIpPrefixes, sIpPrefixes,
221 netElements.getDstNodeId(), netElements.getSrcNodeId());
222 if (visitedPairs.contains(policyPair)) {
223 LOG.trace("PolicyEnforcer: Already visited PolicyPair {}, endpoints {} {} skipped",
224 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
227 LOG.trace("PolicyEnforcer: Visiting PolicyPair {} endpoints {} {}", policyPair,
228 netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
229 visitedPairs.add(policyPair);
232 int priority = 65000;
233 for (RuleGroup rg : activeRulesByConstraints.getValue()) {
234 TenantId tenantId = rg.getContractTenant().getId();
235 IndexedTenant tenant = ctx.getTenant(tenantId);
236 for (Rule rule : rg.getRules()) {
238 // Find all rules in the same traffic direction
239 List<Rule> sameDirectionRules = findRulesInSameDirection(rule, reversedActiveRules);
240 if (sameDirectionRules.isEmpty()) {
241 sameDirectionRules.add(rule);
243 sameDirectionRules = Ordering.from(TenantUtils.RULE_COMPARATOR)
244 .immutableSortedCopy(sameDirectionRules);
246 // Create flows for every pair of rules
247 for (Rule oppositeRule : sameDirectionRules) {
249 // Evaluate which rule has more specific matches
250 Rule ruleWithMatches = findRuleWithSpecificMatches(rule, oppositeRule, tenant);
251 Rule ruleWithActions = mergeRuleActions(rule, oppositeRule, tenant);
252 if (ruleWithMatches == null) {
253 LOG.trace("No matches found for pair of rules {}, {}", rule, oppositeRule);
256 if (ruleWithActions == null) {
257 LOG.trace("No actions found for pair of rules {}, {}", rule, oppositeRule);
261 // Preserve original rule direction
262 Set<Direction> directions = getRuleDirections(rule);
264 for(Direction direction : directions) {
266 // Create list of matches/actions. Also creates chain flows when specific action requires it
267 List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant,
269 List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant,
272 List<ActionBuilder> actions = createActions(ofWriter, netElements, direction,
273 policyPair, tenant, ruleWithActions, false);
276 createFlows(inMatches, actions, netElements, ofWriter, priority);
277 createFlows(outMatches, actions, netElements, ofWriter, priority);
281 // Keep info about what direction has flows already created
282 if (direction.equals(Direction.In)) {
283 directPathFlowsCreated = true;
285 if (direction.equals(Direction.Out)) {
286 reversePathFlowsCreated = true;
289 // Fully resolved Ep groups are saved to prevent duplicates
290 if (directPathFlowsCreated && reversePathFlowsCreated) {
291 LOG.trace("Epg pair added: {}, {} ", netElements.getSrcEpg(), netElements.getDstEpg());
292 resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
300 // Returns appropriate result of resolving
301 if (directPathFlowsCreated && reversePathFlowsCreated) {
302 return PathStatus.both;
303 } else if ((!directPathFlowsCreated && reversePathFlowsCreated) || (directPathFlowsCreated && !reversePathFlowsCreated)) {
304 return PathStatus.partial;
306 return PathStatus.none;
310 private Set<Direction> getRuleDirections(Rule ruleWithMatches) {
311 Set<Direction> directions = new HashSet<>();
312 for (ClassifierRef classifierRef : ruleWithMatches.getClassifierRef()) {
313 if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.In) {
314 directions.add(classifierRef.getDirection());
316 if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.Out) {
317 directions.add(classifierRef.getDirection());
320 if (directions.isEmpty()) {
321 directions.add(Direction.Bidirectional);
326 private Rule mergeRuleActions(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
327 if (oppositeRule.equals(rule)) {
331 Action ruleAction = null;
332 Action oppositeRuleAction = null;
334 // For now, only allow action and chain action is supported
335 for (ActionRef actionRef : rule.getActionRef()) {
336 ActionInstance actionInstance = tenant.getAction(actionRef.getName());
337 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
338 ruleAction = new AllowAction();
340 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
341 ruleAction = new ChainAction();
344 for (ActionRef actionRef : oppositeRule.getActionRef()) {
345 ActionInstance actionInstance = tenant.getAction(actionRef.getName());
346 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
347 oppositeRuleAction = new AllowAction();
349 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
350 oppositeRuleAction = new ChainAction();
354 if (ruleAction == null && oppositeRuleAction == null) {
356 } else if (ruleAction != null && ruleAction.getClass().equals(AllowAction.class)) {
358 } else if (oppositeRuleAction != null && oppositeRuleAction.getClass().equals(AllowAction.class)) {
361 // TODO both rules have chain action - add support for more different chain actions. This works for now
366 private Rule findRuleWithSpecificMatches(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
367 if (oppositeRule.equals(rule)) {
371 // TODO check all classifierRefs
372 ClassifierRef ruleClassifierRef = rule.getClassifierRef().get(0);
373 ClassifierRef oppositeRuleClassifierRef = oppositeRule.getClassifierRef().get(0);
375 ClassifierInstance ruleClassifierInstance = tenant.getClassifier(ruleClassifierRef.getInstanceName());
376 ClassifierInstance oppositeRuleClassifierInstance = tenant.getClassifier(oppositeRuleClassifierRef.getInstanceName());
378 if (ruleClassifierInstance == null) {
379 LOG.trace("Classifier instance not found, ClassifierRef name: {} ", ruleClassifierRef.getInstanceName());
382 if (oppositeRuleClassifierInstance == null) {
383 LOG.trace("Opposite classifier instance not found, ClassifierRef name: {} ", oppositeRuleClassifierRef.getInstanceName());
387 // Check ethertype. Values must be equal
388 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
389 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
390 if ((ruleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
391 && oppositeRuleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)) {
392 if (!ruleParameter.getIntValue().equals(oppositeRuleParameter.getIntValue())) {
393 LOG.trace("Ethertype values are not equal, rule: {}, opposite rule: {} ", rule, oppositeRule);
399 // Check proto if exists. Values must be equal or missing
400 ParameterValue ruleProtoParameter = null;
401 ParameterValue oppositeRuleProtoParameter = null;
402 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
403 if (ruleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
404 ruleProtoParameter = ruleParameter;
407 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
408 if (oppositeRuleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
409 oppositeRuleProtoParameter = oppositeRuleParameter;
413 if (ruleProtoParameter == null || ruleProtoParameter.getIntValue() == null) {
415 } else if (oppositeRuleProtoParameter == null || oppositeRuleProtoParameter.getIntValue() == null) {
417 } else if (!ruleProtoParameter.getIntValue().equals(oppositeRuleProtoParameter.getIntValue())) {
418 LOG.trace("Proto parameters are not equal, rule parameters: {}, opposite rule parameters {} ",
419 ruleProtoParameter, oppositeRuleProtoParameter);
424 // TODO add support for port ranges
425 ParameterValue ruleL4Src = null;
426 ParameterValue oppositeRuleL4Src = null;
427 ParameterValue ruleL4Dst = null;
428 ParameterValue oppositeRuleL4Dst = null;
430 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
431 if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
432 ruleL4Src = ruleParameter;
434 if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
435 ruleL4Dst = ruleParameter;
438 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
439 if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
440 oppositeRuleL4Src = oppositeRuleParameter;
442 if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
443 oppositeRuleL4Dst = oppositeRuleParameter;
447 if (ruleL4Src == null && ruleL4Dst == null && oppositeRuleL4Src == null && oppositeRuleL4Dst == null) {
452 if (ruleL4Src == null && oppositeRuleL4Src != null) {
455 if (ruleL4Src != null && oppositeRuleL4Src == null) {
458 if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
459 && ruleL4Src.equals(oppositeRuleL4Src)) {
462 if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
463 && !ruleL4Src.equals(oppositeRuleL4Src)) {
468 if (ruleL4Dst == null && oppositeRuleL4Dst != null) {
471 if (ruleL4Dst != null && oppositeRuleL4Dst == null) {
474 if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
475 && ruleL4Dst.equals(oppositeRuleL4Dst)) {
478 if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
479 && !ruleL4Dst.equals(oppositeRuleL4Dst)) {
486 private void resolveDestinationEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy reversedPolicy,
487 boolean isReverted) {
488 isReversedPolicy = true;
489 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
490 reversedPolicy, netElements.getSrcEp(), netElements.getDstEp())) {
491 Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
493 Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
495 PolicyPair policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getEpgId(),
496 netElements.getSrcEpOrdinals().getCgId(), netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
497 netElements.getSrcNodeId(), netElements.getDstNodeId());
498 if (visitedReversePairs.contains(policyPair)) {
500 "PolicyEnforcer: Reverse: Already visited PolicyPair {}, endpoints {} {} skipped",
501 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
504 LOG.trace("PolicyEnforcer: Reverse: Visiting: PolicyPair {} via endpoints {} {}",
505 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
506 visitedReversePairs.add(policyPair);
509 int priority = 65000;
510 for (RuleGroup rg : activeRulesByConstraints.getValue()) {
511 TenantId tenantId = rg.getContractTenant().getId();
512 IndexedTenant tenant = ctx.getTenant(tenantId);
513 for (Rule rule : rg.getRules()) {
515 Set<Direction> directions = getRuleDirections(rule);
516 if (directions.isEmpty()) {
520 for(Direction direction : directions) {
522 // When specific direction flows exists, do not create them again
523 if (direction.equals(Direction.In) && reversePathFlowsCreated) {
526 if (direction.equals(Direction.Out) && directPathFlowsCreated) {
530 List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant, rule);
531 List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant, rule);
533 // In case chain action is called here, it has to know that this is reversed policy to set tunnel
535 List<ActionBuilder> inActions = createActions(ofWriter, netElements, Direction.In, policyPair, tenant,
537 List<ActionBuilder> outActions = createActions(ofWriter, netElements, Direction.Out, policyPair, tenant,
540 createFlows(inMatches, inActions, netElements, ofWriter, priority);
541 createFlows(outMatches, outActions, netElements, ofWriter, priority);
543 if (direction.equals(Direction.In)) {
544 reversePathFlowsCreated = true;
546 if (direction.equals(Direction.Out)) {
547 directPathFlowsCreated = true;
552 if (directPathFlowsCreated && reversePathFlowsCreated) {
553 resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
561 private void allowSameEpg(NodeId nodeId, OfWriter ofWriter) throws Exception {
562 for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
563 for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
565 IndexedTenant tenant = ctx.getTenant(sourceEpgKey.getTenantId());
566 if (tenant != null) {
567 EndpointGroup group = tenant.getEndpointGroup(sourceEpgKey.getEgId());
569 LOG.debug("EPG {} does not exit and is used in EP {}", sourceEpgKey, sourceEp.getKey());
572 IntraGroupPolicy igp = group.getIntraGroupPolicy();
574 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
575 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(sourceEpgKey)) {
576 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
577 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
578 if (srcEpFwdCxtOrdinals == null) {
579 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
583 EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
584 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
585 if (dstEpFwdCxtOrdinals == null) {
586 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
590 int destinationEpgId = dstEpFwdCxtOrdinals.getEpgId();
591 int sourceEpgId = srcEpFwdCxtOrdinals.getEpgId();
592 ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(sourceEpgId, destinationEpgId));
593 ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(destinationEpgId, sourceEpgId));
601 // Return list of all rules with opposite direction
602 private List<Rule> findRulesInSameDirection(Rule ruleToResolve, List<Rule> reversedRules) {
603 List<Rule> sameDirectionRules = new ArrayList<>();
604 for (Rule ruleToCompare : reversedRules) {
605 for (ClassifierRef classifierRefToCompare : ruleToCompare.getClassifierRef()) {
606 for (ClassifierRef classifierRefToResolve : ruleToResolve.getClassifierRef()) {
607 if (isDirectionOpposite(classifierRefToCompare.getDirection(), classifierRefToResolve.getDirection())) {
608 sameDirectionRules.add(ruleToCompare);
613 return sameDirectionRules;
616 private boolean isDirectionOpposite(Direction one, Direction two) {
617 return ((one.equals(Direction.In) && two.equals(Direction.Out))
618 || (one.equals(Direction.Out) && two.equals(Direction.In)));
621 private List<Rule> getRules(List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules) {
622 List<Rule> rules = new ArrayList<>();
623 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRule : activeRules) {
624 for (RuleGroup ruleGroup : activeRule.getValue()) {
625 for (Rule rule : ruleGroup.getRules()) {
633 private Flow createArpFlow(Integer fdId) {
635 Long etherType = FlowUtils.ARP;
636 // L2 Classifier so 20,000 for now
637 Integer priority = 20000;
639 MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
641 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
643 Match match = mb.build();
644 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
645 return base().setPriority(priority)
648 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
652 private Flow allowSameEpg(int sourceEpgId, int destinationEpgId) {
654 MatchBuilder mb = new MatchBuilder();
655 addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) sourceEpgId),
656 RegMatch.of(NxmNxReg2.class, (long) destinationEpgId));
657 Match match = mb.build();
658 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
659 FlowBuilder flow = base().setId(flowId)
662 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
666 private Flow allowFromTunnel(NodeConnectorId tunPort) {
668 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
669 addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
670 Match match = mb.build();
671 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
672 FlowBuilder flow = base().setId(flowId)
675 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
680 private List<MatchBuilder> createMatches(Direction direction, PolicyPair policyPair, IndexedTenant contractTenant,
682 Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
683 Set<ClassifierDefinitionId> classifiers = new HashSet<>();
684 for (ClassifierRef cr : rule.getClassifierRef()) {
686 if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
687 && !cr.getDirection().equals(direction)) {
691 // XXX - TODO - implement connection tracking (requires openflow
692 // extension and data plane support - in 2.4. Will need to handle
693 // case where we are working with mix of nodes.
695 ClassifierInstance ci = contractTenant.getClassifier(cr.getInstanceName());
697 // XXX TODO fail the match and raise an exception
698 LOG.warn("Classifier instance {} not found", cr.getInstanceName().getValue());
701 Classifier classifier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
702 if (classifier == null) {
703 // XXX TODO fail the match and raise an exception
704 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
707 classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
708 for (ParameterValue v : ci.getParameterValue()) {
709 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
710 if (v.getIntValue() != null || v.getStringValue() != null || v.getRangeValue() != null) {
711 paramsFromClassifier.put(v.getName().getValue(), v);
714 if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
715 throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
716 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
721 if (classifiers.isEmpty()) {
724 List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
725 List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
726 for (Map<String, ParameterValue> params : derivedParamsByName) {
727 List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
728 if (policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
729 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, null));
730 } else if (!policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
731 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
732 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, null));
734 } else if (policyPair.consumerEicIpPrefixes.isEmpty() && !policyPair.providerEicIpPrefixes.isEmpty()) {
735 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
736 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, dIpPrefix));
739 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
740 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
741 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, dIpPrefix));
745 for (ClassifierDefinitionId clDefId : classifiers) {
746 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
747 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
748 if (!result.isSuccessfull()) {
749 // TODO consider different handling.
750 throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName()
751 + ".\nCause: " + result.getErrorMessage());
753 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
755 flowMatchBuilders.addAll(matchBuildersToResolve);
757 return flowMatchBuilders;
760 private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction, PolicyPair policyPair,
761 IndexedTenant contractTenant, Rule rule, boolean isReversedDirection) {
762 List<ActionBuilder> actionBuilderList = new ArrayList<>();
763 if (rule.getActionRef() != null) {
765 // Pre-sort by references using order, then name
766 List<ActionRef> actionRefList = new ArrayList<>(rule.getActionRef());
767 Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
769 for (ActionRef actionRule : actionRefList) {
770 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
771 if (actionInstance == null) {
772 // XXX TODO fail the match and raise an exception
773 LOG.warn("Action instance {} not found", actionRule.getName().getValue());
776 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
777 if (action == null) {
778 // XXX TODO fail the match and raise an exception
779 LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
783 Map<String, Object> params = new HashMap<>();
784 if (actionInstance.getParameterValue() != null) {
785 for (ParameterValue v : actionInstance.getParameterValue()) {
786 if (v.getName() == null)
788 if (v.getIntValue() != null) {
789 params.put(v.getName().getValue(), v.getIntValue());
790 } else if (v.getStringValue() != null) {
791 params.put(v.getName().getValue(), v.getStringValue());
795 if (isReversedDirection) {
796 direction = reverse(direction);
799 // Convert the GBP Action to one or more OpenFlow Actions
800 if (!(actionRefList.indexOf(actionRule) == (actionRefList.size() - 1)
801 && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId())))) {
802 actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(), netElements,
803 policyPair, ofWriter, ctx, direction);
808 return actionBuilderList;
811 private Direction reverse(Direction direction) {
812 if (direction.equals(Direction.In)) {
813 return Direction.Out;
815 else if(direction.equals(Direction.Out)) {
819 return Direction.Bidirectional;
823 private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList, NetworkElements netElements,
824 OfWriter ofWriter, int priority) {
825 FlowBuilder flow = base().setPriority(priority);
826 if(flowMatchBuilders == null) {
829 for (MatchBuilder mb : flowMatchBuilders) {
830 Match match = mb.build();
831 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "cg", match);
832 flow.setMatch(match).setId(flowId).setPriority(priority);
834 // If destination is External, the last Action ALLOW must be changed to goto
835 // NAT/External table.
836 // If actionBuilderList is empty (we removed the last Allow) then go straight to
837 // ExternalMapper table.
839 List<ExternalImplicitGroup> eigs = ctx.getTenant(netElements.getDstEp().getTenant())
842 .getExternalImplicitGroup();
843 if (EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
844 flow.setInstructions(instructions(gotoEgressNatInstruction));
845 } else if (actionBuilderList == null) {
846 //TODO - analyse, what happen for unknown action, SFC, etc.
847 LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
849 } else if (actionBuilderList.isEmpty()) {
850 flow.setInstructions(instructions(gotoExternalInstruction));
852 flow.setInstructions(instructions(applyActionIns(actionBuilderList), gotoExternalInstruction));
854 ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
858 private MatchBuilder createBaseMatch(Direction direction, PolicyPair policyPair, IpPrefix sIpPrefix,
859 IpPrefix dIpPrefix) {
860 MatchBuilder baseMatch = new MatchBuilder();
861 if (direction.equals(Direction.In)) {
862 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.consumerEpgId),
863 RegMatch.of(NxmNxReg1.class, (long) policyPair.consumerCondGrpId),
864 RegMatch.of(NxmNxReg2.class, (long) policyPair.providerEpgId),
865 RegMatch.of(NxmNxReg3.class, (long) policyPair.providerCondGrpId));
866 if (sIpPrefix != null) {
867 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
869 if (dIpPrefix != null) {
870 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
873 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.providerEpgId),
874 RegMatch.of(NxmNxReg1.class, (long) policyPair.providerCondGrpId),
875 RegMatch.of(NxmNxReg2.class, (long) policyPair.consumerEpgId),
876 RegMatch.of(NxmNxReg3.class, (long) policyPair.consumerCondGrpId));
877 if (sIpPrefix != null) {
878 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
880 if (dIpPrefix != null) {
881 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
887 private Layer3Match createLayer3Match(IpPrefix ipPrefix, boolean isSrc) {
888 if (ipPrefix.getIpv4Prefix() != null) {
890 return new Ipv4MatchBuilder().setIpv4Source(ipPrefix.getIpv4Prefix()).build();
892 return new Ipv4MatchBuilder().setIpv4Destination(ipPrefix.getIpv4Prefix()).build();
896 return new Ipv6MatchBuilder().setIpv6Source(ipPrefix.getIpv6Prefix()).build();
898 return new Ipv6MatchBuilder().setIpv6Destination(ipPrefix.getIpv6Prefix()).build();
903 // TODO: move to a common utils for all renderers
904 private List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
905 Endpoint consEp, Endpoint provEp) {
906 List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
907 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
908 EndpointConstraint consEpConstraint = cell.getRowKey();
909 EndpointConstraint provEpConstraint = cell.getColumnKey();
910 if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
911 rulesWithEpConstraints.add(cell);
914 return rulesWithEpConstraints;
917 private boolean epMatchesConstraint(Endpoint ep, EndpointConstraint constraint) {
918 List<ConditionName> epConditions = Collections.emptyList();
919 if (ep.getCondition() != null) {
920 epConditions = ep.getCondition();
922 return constraint.getConditionSet().matches(epConditions);
925 private enum PathStatus { both, partial, none }
927 public static boolean checkPolicyOrientation() {
928 return isReversedPolicy;
932 * Private internal class for ordering Actions in Rules. The order is
933 * determined first by the value of the order parameter, with the lower
934 * order actions being applied first; for Actions with either the same order
935 * or no order, ordering is lexicographical by name.
937 private static class ActionRefComparator implements Comparator<ActionRef> {
939 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
942 public int compare(ActionRef arg0, ActionRef arg1) {
943 return ComparisonChain.start()
944 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
945 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
952 public static class PolicyPair {
954 private final int consumerEpgId;
955 private final int providerEpgId;
956 private final int consumerCondGrpId;
957 private final int providerCondGrpId;
958 private final Set<IpPrefix> consumerEicIpPrefixes;
959 private final Set<IpPrefix> providerEicIpPrefixes;
960 private final NodeId consumerEpNodeId;
961 private final NodeId providerEpNodeId;
963 public PolicyPair(int consumerEpgId, int providerEpgId, int consumerCondGrpId, int providerCondGrpId,
964 Set<IpPrefix> consumerEicIpPrefixes, Set<IpPrefix> providerEicIpPrefixes, NodeId consumerEpNodeId, NodeId providerEpNodeId) {
966 this.consumerEpgId = consumerEpgId;
967 this.providerEpgId = providerEpgId;
968 this.consumerCondGrpId = consumerCondGrpId;
969 this.providerCondGrpId = providerCondGrpId;
970 this.consumerEicIpPrefixes = consumerEicIpPrefixes;
971 this.providerEicIpPrefixes = providerEicIpPrefixes;
972 this.consumerEpNodeId = consumerEpNodeId;
973 this.providerEpNodeId = providerEpNodeId;
976 public int getConsumerEpgId() {
977 return consumerEpgId;
980 public int getProviderEpgId() {
981 return providerEpgId;
984 public NodeId getConsumerEpNodeId() {
985 return consumerEpNodeId;
988 public NodeId getProviderEpNodeId() {
989 return providerEpNodeId;
993 public int hashCode() {
994 final int prime = 31;
996 result = prime * result + ((providerEicIpPrefixes == null) ? 0 : providerEicIpPrefixes.hashCode());
997 result = prime * result + providerCondGrpId;
998 result = prime * result + providerEpgId;
999 result = prime * result + ((consumerEicIpPrefixes == null) ? 0 : consumerEicIpPrefixes.hashCode());
1000 result = prime * result + consumerCondGrpId;
1001 result = prime * result + consumerEpgId;
1002 result = prime * result + ((consumerEpNodeId == null) ? 0 : consumerEpNodeId.hashCode());
1003 result = prime * result + ((providerEpNodeId == null) ? 0 : providerEpNodeId.hashCode());
1009 public boolean equals(Object obj) {
1014 if (getClass() != obj.getClass())
1016 PolicyPair other = (PolicyPair) obj;
1017 if (providerEicIpPrefixes == null) {
1018 if (other.providerEicIpPrefixes != null) {
1021 } else if (!providerEicIpPrefixes.equals(other.providerEicIpPrefixes)) {
1024 if (consumerEicIpPrefixes == null) {
1025 if (other.consumerEicIpPrefixes != null) {
1028 } else if (!consumerEicIpPrefixes.equals(other.consumerEicIpPrefixes)) {
1031 if (consumerEpNodeId == null) {
1032 if (other.consumerEpNodeId != null) {
1035 } else if (!consumerEpNodeId.getValue().equals(other.consumerEpNodeId.getValue())) {
1038 if (providerEpNodeId == null) {
1039 if (other.providerEpNodeId != null) {
1042 } else if (!providerEpNodeId.getValue().equals(other.providerEpNodeId.getValue())) {
1045 return (providerCondGrpId == other.providerCondGrpId)
1046 && (providerEpgId == other.providerEpgId)
1047 && (consumerCondGrpId == other.consumerCondGrpId)
1048 && (consumerEpgId == other.consumerEpgId);
1053 public String toString() {
1054 return "consumerEPG: " + consumerEpgId +
1055 "consumerCG: " + consumerCondGrpId +
1056 "providerEPG: " + providerEpgId +
1057 "providerCG: " + providerCondGrpId +
1058 "consumerEpNodeId: " + consumerEpNodeId +
1059 "providerEpNodeId: " + providerEpNodeId +
1060 "consumerEicIpPrefixes: " + consumerEicIpPrefixes +
1061 "providerEicIpPrefixes: " + providerEicIpPrefixes;
1065 public class NetworkElements {
1067 private final Endpoint srcEp;
1068 private final Endpoint dstEp;
1069 private final EgKey srcEpg;
1070 private final EgKey dstEpg;
1071 private NodeId srcNodeId;
1072 private NodeId dstNodeId;
1073 private final NodeId localNodeId;
1074 private EndpointFwdCtxOrdinals srcEpOrdinals;
1075 private EndpointFwdCtxOrdinals dstEpOrdinals;
1077 public NetworkElements(Endpoint srcEp, Endpoint dstEp, EgKey srcEpg, EgKey dstEpg, NodeId nodeId, OfContext ctx) throws Exception {
1080 this.srcEpg = srcEpg;
1081 this.dstEpg = dstEpg;
1082 this.localNodeId = nodeId;
1083 this.srcEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);
1084 if (this.srcEpOrdinals == null) {
1085 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
1088 this.dstEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
1089 if (this.dstEpOrdinals == null) {
1090 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
1093 if (dstEp.getAugmentation(OfOverlayContext.class) != null) {
1094 this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();
1096 if (srcEp.getAugmentation(OfOverlayContext.class) != null) {
1097 this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();
1102 public Endpoint getSrcEp() {
1107 public Endpoint getDstEp() {
1111 public EgKey getSrcEpg() {
1115 public EgKey getDstEpg() {
1119 public NodeId getSrcNodeId() {
1124 public NodeId getDstNodeId() {
1129 public NodeId getLocalNodeId() {
1134 public EndpointFwdCtxOrdinals getSrcEpOrdinals() {
1135 return srcEpOrdinals;
1139 public EndpointFwdCtxOrdinals getDstEpOrdinals() {
1140 return dstEpOrdinals;