import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import javax.annotation.concurrent.Immutable;
+import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
+import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.dto.EgKey;
+import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint;
+import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
+import org.opendaylight.groupbasedpolicy.dto.Policy;
+import org.opendaylight.groupbasedpolicy.dto.RuleGroup;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
-import org.opendaylight.groupbasedpolicy.resolver.EgKey;
-import org.opendaylight.groupbasedpolicy.resolver.EndpointConstraint;
-import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
-import org.opendaylight.groupbasedpolicy.resolver.Policy;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
-import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
+import org.opendaylight.groupbasedpolicy.util.TenantUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup.IntraGroupPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.ListMultimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.Table.Cell;
/**
- * Manage the table that enforces policy on the traffic. Traffic is denied
- * unless specifically allowed by policy
+ * <h1>Manage the table that enforces policy on the traffic. Traffic is denied
+ * unless specifically allowed by policy (table=4)</h1>
+ *
+ * In policy enforcer, according to current {@link Policy} specific traffic is sent to SFC (nsp and nsi is set), or from SFC
+ * to some {@link Endpoint} or to another classifier.
+ * <p>
+ * <i>Tunnel/overlay flows</i><br>
+ * Priority = 65000 (if more flows, decrements)<br>
+ * Matches:<br>
+ * - ethertype (tcp, tcp6, ipv6, icmp or missing)<br>
+ * - Reg0 {@link NxmNxReg0}<br>
+ * - Reg1 {@link NxmNxReg1}<br>
+ * - Reg2 {@link NxmNxReg2}<br>
+ * - Reg3 {@link NxmNxReg3}<br>
+ * - L3 for src_ip_prefix (if exists)<br>
+ * - L3 for dst_ip_prefix (if exists)<br>
+ * Actions:<br>
+ * - set nsi (only chain action)<br>
+ * - set nsp (only chain action)<br>
+ * - {@link GoToTable} EXTERNAL MAPPER table<br>
+ *<p>
+ * <i>Allow from tunnel flow</i><br>
+ * Priority = 65000<br>
+ * Matches:<br>
+ * - Reg1 (set to 0xffffff) {@link NxmNxReg1}<br>
+ * - in_port (should be tunnel port) {@link NodeConnectorId}<br>
+ * Actions:<br>
+ * - output:port (Reg7) {@link NxmNxReg7}<br>
+ * <p>
+ * Traffic is sent from one {@link EndpointGroup} to the same EPG
+ * <p>
+ * <i>Allow from same EPG flow</i><br>
+ * Priority = 65000<br>
+ * Matches:<br>
+ * - Reg0 {@link NxmNxReg0}<br>
+ * - Reg2 {@link NxmNxReg2}<br>
+ * Actions:<br>
+ * - output:port (Reg7) {@link NxmNxReg7}
+ * <p>
+ * <i>Arp flow</i><br>
+ * Priority = 20000<br>
+ * Matches:<br>
+ * - ethernet match (arp)<br>
+ * - Reg5 {@link NxmNxReg5}<br>
+ * Actions:<br>
+ * - output:port (Reg7) {@link NxmNxReg7}
+ *
*/
public class PolicyEnforcer extends FlowTable {
- protected static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
-
- public static short TABLE_ID = 3;
+ private static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
+ public static short TABLE_ID;
+ private static boolean isReversedPolicy;
+ private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoEgressNatInstruction;
+ private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoExternalInstruction;
+ private HashSet<PolicyPair> visitedPairs = new HashSet<>();
+ private HashSet<PolicyPair> visitedReversePairs = new HashSet<>();
+ private List<Rule> reversedActiveRules = new ArrayList<>();
+ private ListMultimap<EgKey, EgKey> resolvedEpgPairs = ArrayListMultimap.create();
+ private boolean directPathFlowsCreated = false;
+ private boolean reversePathFlowsCreated = false;
public PolicyEnforcer(OfContext ctx, short tableId) {
super(ctx);
- this.TABLE_ID=tableId;
+ TABLE_ID = tableId;
+ isReversedPolicy = false;
+ gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
+ gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER());
+ }
+
+ private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
+ return gotoEgressNatInstruction;
}
+ private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
+ return gotoExternalInstruction;
+ }
@Override
public short getTableId() {
}
@Override
- public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
+ public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
- flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
+ ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
- NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class);
+ NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
if (tunPort != null) {
- flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
+ ofWriter.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
}
- HashSet<CgPair> visitedPairs = new HashSet<>();
+ visitedPairs = new HashSet<>();
+ reversedActiveRules = new ArrayList<>();
+ visitedReversePairs = new HashSet<>();
+ resolvedEpgPairs = ArrayListMultimap.create();
// Used for ARP flows
Set<Integer> fdIds = new HashSet<>();
- for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
- for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
- Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
- for (EgKey dstEpgKey : peers) {
- Set<Endpoint> dstEndpoints = new HashSet<>();
- dstEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey));
- dstEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(dstEpgKey));
- for (Endpoint dstEp : dstEndpoints) {
- // mEPG ordinals
- EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
- policyInfo, srcEp);
- EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
- policyInfo, dstEp);
- int dcgId = dstEpFwdCxtOrds.getCgId();
- int depgId = dstEpFwdCxtOrds.getEpgId();
- int scgId = srcEpFwdCxtOrds.getCgId();
- int sepgId = srcEpFwdCxtOrds.getEpgId();
- NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
- fdIds.add(srcEpFwdCxtOrds.getFdId());
-
- Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
- for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints: getActiveRulesBetweenEps(policy, dstEp, srcEp)) {
- Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
- .getL3EpPrefixes());
- Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
- .getL3EpPrefixes());
- CgPair p = new CgPair(depgId, sepgId, dcgId, scgId, dIpPrefixes, sIpPrefixes);
- if (visitedPairs.contains(p))
- continue;
- visitedPairs.add(p);
- syncPolicy(flowMap, netElements, activeRulesByConstraints.getValue(), p);
+ for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
+ for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
+ Set<EgKey> peers = ctx.getCurrentPolicy().getPeers(sourceEpgKey);
+ for (EgKey destinationEpgKey : peers) {
+
+ Set<Endpoint> destinationEndpoints = new HashSet<>();
+ destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(destinationEpgKey));
+ destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(destinationEpgKey));
+ for (Endpoint destinationEp : destinationEndpoints) {
+
+ EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
+ if (srcEpFwdCxtOrdinals == null) {
+ LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", sourceEp);
+ continue;
}
- // Reverse
- policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
- for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(policy, srcEp, dstEp)) {
- Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
- .getL3EpPrefixes());
- Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
- .getL3EpPrefixes());
- CgPair p = new CgPair(sepgId, depgId, scgId, dcgId, sIpPrefixes, dIpPrefixes);
- if (visitedPairs.contains(p))
- continue;
- visitedPairs.add(p);
- syncPolicy(flowMap, netElements, activeRulesByConstraints.getValue(), p);
+ EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEp);
+ if (dstEpFwdCxtOrdinals == null) {
+ LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEp);
+ continue;
+ }
+
+ fdIds.add(srcEpFwdCxtOrdinals.getFdId());
+ NetworkElements netElements = new NetworkElements(sourceEp, destinationEp, sourceEpgKey,
+ destinationEpgKey, nodeId, ctx);
+
+ // Get policy in both directions
+ Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destinationEpgKey, sourceEpgKey);
+ Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpgKey, destinationEpgKey);
+ reversedActiveRules = getRules(getActiveRulesBetweenEps(destinationEpgPolicy, sourceEp, destinationEp));
+
+ // Resolve flows in both directions if possible according to policy. Get back status of resolution
+ PathStatus status = resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy);
+
+ // When source Epg policy creates no flows, destination Epg policy has to be resolved
+ if (status.equals(PathStatus.none)) {
+ resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, false);
+ }
+ // When source Epg policy creates flows only in one direction, the other direction has to be
+ // created here. Is essential to revert directions to prevent flow overriding and incorrect nsp
+ // evaluation
+ else if (status.equals(PathStatus.partial)) {
+ resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, true);
}
}
}
}
// Allow same EPG
- // Set<Endpoint> visitedEps = new HashSet<>();
- for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
- // visitedEps.add(srcEp);
- for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
-
- IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
- EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
- IntraGroupPolicy igp = group.getIntraGroupPolicy();
-
- if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
- for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
- // mEPG ordinals
- // if(visitedEps.contains(dstEp)) {
- // continue;
- // }
- // visitedEps.add(dstEp);
- EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
- policyInfo, srcEp);
- EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
- policyInfo, dstEp);
- int depgId = dstEpFwdCxtOrds.getEpgId();
- int sepgId = srcEpFwdCxtOrds.getEpgId();
- flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
- flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
+ allowSameEpg(nodeId, ofWriter);
+
+ // Write ARP flows per flood domain
+ for (Integer fdId : fdIds) {
+ ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
+ }
+ }
+
+ private PathStatus resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy) {
+ isReversedPolicy = false;
+ directPathFlowsCreated = false;
+ reversePathFlowsCreated = false;
+
+ for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
+ directPolicy, netElements.getDstEp(), netElements.getSrcEp())) {
+ Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
+ .getL3EpPrefixes());
+ Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
+ .getL3EpPrefixes());
+
+ int priority = 65000;
+ for (RuleGroup rg : activeRulesByConstraints.getValue()) {
+ TenantId tenantId = rg.getContractTenant().getId();
+ IndexedTenant tenant = ctx.getTenant(tenantId);
+ for (Rule rule : rg.getRules()) {
+
+ // Find all rules in the same traffic direction
+ List<Rule> sameDirectionRules = findRulesInSameDirection(rule, reversedActiveRules);
+ if (sameDirectionRules.isEmpty()) {
+ sameDirectionRules.add(rule);
+ }
+ sameDirectionRules = Ordering.from(TenantUtils.RULE_COMPARATOR)
+ .immutableSortedCopy(sameDirectionRules);
+
+ // Create flows for every pair of rules
+ for (Rule oppositeRule : sameDirectionRules) {
+
+ // Evaluate which rule has more specific matches
+ Rule ruleWithMatches = findRuleWithSpecificMatches(rule, oppositeRule, tenant);
+ Rule ruleWithActions = mergeRuleActions(rule, oppositeRule, tenant);
+ if (ruleWithMatches == null) {
+ LOG.trace("No matches found for pair of rules {}, {}", rule, oppositeRule);
+ continue;
+ }
+ if (ruleWithActions == null) {
+ LOG.trace("No actions found for pair of rules {}, {}", rule, oppositeRule);
+ continue;
+ }
+ PolicyPair policyPair = null;
+ if (rule.equals(ruleWithMatches)) {
+ policyPair = new PolicyPair(netElements.getDstEpOrdinals().getEpgId(),
+ netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getCgId(),
+ netElements.getSrcEpOrdinals().getCgId(), dIpPrefixes, sIpPrefixes,
+ netElements.getDstNodeId(), netElements.getSrcNodeId());
+ } else {
+ policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(),
+ netElements.getDstEpOrdinals().getEpgId(), netElements.getSrcEpOrdinals().getCgId(),
+ netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
+ netElements.getSrcNodeId(), netElements.getDstNodeId());
+ }
+ LOG.trace("PolicyEnforcer: Visiting PolicyPair {} endpoints {} {}", policyPair,
+ netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
+
+ // Preserve original rule direction
+ Set<Direction> directions = getRuleDirections(rule);
+
+ for(Direction direction : directions) {
+
+ // Create list of matches/actions. Also creates chain flows when specific action requires it
+ List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant,
+ ruleWithMatches);
+ List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant,
+ ruleWithMatches);
+
+ List<ActionBuilder> actions = createActions(ofWriter, netElements, direction,
+ policyPair, tenant, ruleWithActions, false);
+
+ // Compose flows
+ createFlows(inMatches, actions, netElements, ofWriter, priority);
+ createFlows(outMatches, actions, netElements, ofWriter, priority);
+
+ priority -= 1;
+
+ // Keep info about what direction has flows already created
+ if (direction.equals(Direction.In)) {
+ directPathFlowsCreated = true;
+ }
+ if (direction.equals(Direction.Out)) {
+ reversePathFlowsCreated = true;
+ }
+
+ // Fully resolved Ep groups are saved to prevent duplicates
+ if (directPathFlowsCreated && reversePathFlowsCreated) {
+ LOG.trace("Epg pair added: {}, {} ", netElements.getSrcEpg(), netElements.getDstEpg());
+ resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
+ }
+ }
}
}
}
- }
- // Write ARP flows per flood domain.
- for (Integer fdId : fdIds) {
- flowMap.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
+ }
+ // Returns appropriate result of resolving
+ if (directPathFlowsCreated && reversePathFlowsCreated) {
+ return PathStatus.both;
+ } else if ((!directPathFlowsCreated && reversePathFlowsCreated) || (directPathFlowsCreated && !reversePathFlowsCreated)) {
+ return PathStatus.partial;
+ } else {
+ return PathStatus.none;
}
}
- private Flow createArpFlow(Integer fdId) {
+ private Set<Direction> getRuleDirections(Rule ruleWithMatches) {
+ Set<Direction> directions = new HashSet<>();
+ for (ClassifierRef classifierRef : ruleWithMatches.getClassifierRef()) {
+ if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.In) {
+ directions.add(classifierRef.getDirection());
+ }
+ if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.Out) {
+ directions.add(classifierRef.getDirection());
+ }
+ }
+ if (directions.isEmpty()) {
+ directions.add(Direction.Bidirectional);
+ }
+ return directions;
+ }
- Long etherType = FlowUtils.ARP;
- // L2 Classifier so 20,000 for now
- Integer priority = 20000;
- FlowId flowid = new FlowId(new StringBuilder().append("arp")
- .append("|")
- .append(etherType)
- .append("|")
- .append(fdId)
- .toString());
+ private Rule mergeRuleActions(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
+ if (oppositeRule.equals(rule)) {
+ return rule;
+ }
- MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
+ Action ruleAction = null;
+ Action oppositeRuleAction = null;
- addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
+ // For now, only allow action and chain action is supported
+ for (ActionRef actionRef : rule.getActionRef()) {
+ ActionInstance actionInstance = tenant.getAction(actionRef.getName());
+ if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
+ ruleAction = new AllowAction();
+ }
+ if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
+ ruleAction = new ChainAction();
+ }
+ }
+ for (ActionRef actionRef : oppositeRule.getActionRef()) {
+ ActionInstance actionInstance = tenant.getAction(actionRef.getName());
+ if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
+ oppositeRuleAction = new AllowAction();
+ }
+ if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
+ oppositeRuleAction = new ChainAction();
+ }
+ }
- Flow flow = base().setPriority(priority)
- .setId(flowid)
- .setMatch(mb.build())
- .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
- .build();
- return flow;
+ if (ruleAction == null && oppositeRuleAction == null) {
+ return null;
+ } else if (ruleAction != null && ruleAction.getClass().equals(AllowAction.class)) {
+ return oppositeRule;
+ } else if (oppositeRuleAction != null && oppositeRuleAction.getClass().equals(AllowAction.class)) {
+ return rule;
+ } else {
+ // TODO both rules have chain action - add support for more different chain actions. This works for now
+ return rule;
+ }
}
- private Flow allowSameEpg(int sepgId, int depgId) {
+ private Rule findRuleWithSpecificMatches(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
+ if (oppositeRule.equals(rule)) {
+ return rule;
+ }
- FlowId flowId = new FlowId(new StringBuilder().append("intraallow|").append(sepgId).toString());
- MatchBuilder mb = new MatchBuilder();
- addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
- RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
- FlowBuilder flow = base().setId(flowId)
- .setMatch(mb.build())
- .setPriority(65000)
- .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
- return flow.build();
- }
+ // TODO check all classifierRefs
+ ClassifierRef ruleClassifierRef = rule.getClassifierRef().get(0);
+ ClassifierRef oppositeRuleClassifierRef = oppositeRule.getClassifierRef().get(0);
- private Flow allowFromTunnel(NodeConnectorId tunPort) {
+ ClassifierInstance ruleClassifierInstance = tenant.getClassifier(ruleClassifierRef.getInstanceName());
+ ClassifierInstance oppositeRuleClassifierInstance = tenant.getClassifier(oppositeRuleClassifierRef.getInstanceName());
- FlowId flowId = new FlowId("tunnelallow");
- MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
- addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
- FlowBuilder flow = base().setId(flowId)
- .setMatch(mb.build())
- .setPriority(65000)
- .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
- return flow.build();
+ if (ruleClassifierInstance == null) {
+ LOG.trace("Classifier instance not found, ClassifierRef name: {} ", ruleClassifierRef.getInstanceName());
+ return null;
+ }
+ if (oppositeRuleClassifierInstance == null) {
+ LOG.trace("Opposite classifier instance not found, ClassifierRef name: {} ", oppositeRuleClassifierRef.getInstanceName());
+ return null;
+ }
- }
+ // Check ethertype. Values must be equal
+ for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
+ for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
+ if ((ruleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
+ && oppositeRuleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)) {
+ if (!ruleParameter.getIntValue().equals(oppositeRuleParameter.getIntValue())) {
+ LOG.trace("Ethertype values are not equal, rule: {}, opposite rule: {} ", rule, oppositeRule);
+ return null;
+ }
+ }
+ }
+ }
+ // Check proto if exists. Values must be equal or missing
+ ParameterValue ruleProtoParameter = null;
+ ParameterValue oppositeRuleProtoParameter = null;
+ for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
+ if (ruleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
+ ruleProtoParameter = ruleParameter;
+ }
+ }
+ for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
+ if (oppositeRuleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
+ oppositeRuleProtoParameter = oppositeRuleParameter;
+ }
+ }
- private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> rgs, CgPair p) {
- int priority = 65000;
- for (RuleGroup rg : rgs) {
- TenantId tenantId = rg.getContractTenant().getId();
- IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
- for (Rule r : rg.getRules()) {
- syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority);
- syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority);
+ if (ruleProtoParameter == null || ruleProtoParameter.getIntValue() == null) {
+ return oppositeRule;
+ } else if (oppositeRuleProtoParameter == null || oppositeRuleProtoParameter.getIntValue() == null) {
+ return rule;
+ } else if (!ruleProtoParameter.getIntValue().equals(oppositeRuleProtoParameter.getIntValue())) {
+ LOG.trace("Proto parameters are not equal, rule parameters: {}, opposite rule parameters {} ",
+ ruleProtoParameter, oppositeRuleProtoParameter);
+ return null;
+ }
+
+ // Check ports
+ // TODO add support for port ranges
+ ParameterValue ruleL4Src = null;
+ ParameterValue oppositeRuleL4Src = null;
+ ParameterValue ruleL4Dst = null;
+ ParameterValue oppositeRuleL4Dst = null;
- priority -= 1;
+ for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
+ if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
+ ruleL4Src = ruleParameter;
+ }
+ if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
+ ruleL4Dst = ruleParameter;
+ }
+ }
+ for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
+ if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
+ oppositeRuleL4Src = oppositeRuleParameter;
+ }
+ if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
+ oppositeRuleL4Dst = oppositeRuleParameter;
}
}
- }
- /**
- * Private internal class for ordering Actions in Rules. The order is
- * determined first by the value of the order parameter, with the lower
- * order actions being applied first; for Actions with either the same order
- * or no order, ordering is lexicographical by name.
- */
- private static class ActionRefComparator implements Comparator<ActionRef> {
+ if (ruleL4Src == null && ruleL4Dst == null && oppositeRuleL4Src == null && oppositeRuleL4Dst == null) {
+ return rule;
+ }
- public static final ActionRefComparator INSTANCE = new ActionRefComparator();
+ // Source rules
+ if (ruleL4Src == null && oppositeRuleL4Src != null) {
+ return oppositeRule;
+ }
+ if (ruleL4Src != null && oppositeRuleL4Src == null) {
+ return rule;
+ }
+ if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
+ && ruleL4Src.equals(oppositeRuleL4Src)) {
+ return rule;
+ }
+ if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
+ && !ruleL4Src.equals(oppositeRuleL4Src)) {
+ return null;
+ }
- @Override
- public int compare(ActionRef arg0, ActionRef arg1) {
- return ComparisonChain.start()
- .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
- .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
- .result();
+ // Destination rules
+ if (ruleL4Dst == null && oppositeRuleL4Dst != null) {
+ return oppositeRule;
+ }
+ if (ruleL4Dst != null && oppositeRuleL4Dst == null) {
+ return rule;
+ }
+ if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
+ && ruleL4Dst.equals(oppositeRuleL4Dst)) {
+ return rule;
+ }
+ if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
+ && !ruleL4Dst.equals(oppositeRuleL4Dst)) {
+ return null;
}
+ return null;
}
- private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
- Direction direction, int priority) {
- /*
- * Create the ordered action list. The implicit action is "allow", and
- * is therefore always in the list
- *
- * TODO: revisit implicit vs. default for "allow" TODO: look into
- * incorporating operational policy for actions
- */
-
- // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
- // referencing in sort
- List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
- if (rule.getActionRef() != null) {
- /*
- * Pre-sort by references using order, then name
- */
- List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
- Collections.sort(arl, ActionRefComparator.INSTANCE);
+ private void resolveDestinationEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy reversedPolicy,
+ boolean isReverted) {
+ isReversedPolicy = true;
+ for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
+ reversedPolicy, netElements.getSrcEp(), netElements.getDstEp())) {
+ Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
+ .getL3EpPrefixes());
+ Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
+ .getL3EpPrefixes());
+ PolicyPair policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getEpgId(),
+ netElements.getSrcEpOrdinals().getCgId(), netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
+ netElements.getSrcNodeId(), netElements.getDstNodeId());
+ if (visitedReversePairs.contains(policyPair)) {
+ LOG.trace(
+ "PolicyEnforcer: Reverse: Already visited PolicyPair {}, endpoints {} {} skipped",
+ policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
+ continue;
+ } else {
+ LOG.trace("PolicyEnforcer: Reverse: Visiting: PolicyPair {} via endpoints {} {}",
+ policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
+ visitedReversePairs.add(policyPair);
- for (ActionRef actionRule : arl) {
- ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
- if (actionInstance == null) {
- // XXX TODO fail the match and raise an exception
- LOG.warn("Action instance {} not found", actionRule.getName().getValue());
- return;
- }
- Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
- if (action == null) {
- // XXX TODO fail the match and raise an exception
- LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
- return;
- }
+ }
+ int priority = 65000;
+ for (RuleGroup rg : activeRulesByConstraints.getValue()) {
+ TenantId tenantId = rg.getContractTenant().getId();
+ IndexedTenant tenant = ctx.getTenant(tenantId);
+ for (Rule rule : rg.getRules()) {
+
+ Set<Direction> directions = getRuleDirections(rule);
+ if (directions.isEmpty()) {
+ continue;
+ }
- Map<String, Object> params = new HashMap<>();
- if (actionInstance.getParameterValue() != null) {
- for (ParameterValue v : actionInstance.getParameterValue()) {
- if (v.getName() == null)
+ for(Direction direction : directions) {
+
+ // When specific direction flows exists, do not create them again
+ if (direction.equals(Direction.In) && reversePathFlowsCreated) {
continue;
- if (v.getIntValue() != null) {
- params.put(v.getName().getValue(), v.getIntValue());
- } else if (v.getStringValue() != null) {
- params.put(v.getName().getValue(), v.getStringValue());
+ }
+ if (direction.equals(Direction.Out) && directPathFlowsCreated) {
+ continue;
+ }
+
+ List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant, rule);
+ List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant, rule);
+
+ // In case chain action is called here, it has to know that this is reversed policy to set tunnel
+ // ordinal correctly
+ List<ActionBuilder> inActions = createActions(ofWriter, netElements, Direction.In, policyPair, tenant,
+ rule, isReverted);
+ List<ActionBuilder> outActions = createActions(ofWriter, netElements, Direction.Out, policyPair, tenant,
+ rule, isReverted);
+
+ createFlows(inMatches, inActions, netElements, ofWriter, priority);
+ createFlows(outMatches, outActions, netElements, ofWriter, priority);
+
+ if (direction.equals(Direction.In)) {
+ reversePathFlowsCreated = true;
+ }
+ if (direction.equals(Direction.Out)) {
+ directPathFlowsCreated = true;
+ }
+
+ priority -= 1;
+
+ if (directPathFlowsCreated && reversePathFlowsCreated) {
+ resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void allowSameEpg(NodeId nodeId, OfWriter ofWriter) throws Exception {
+ for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
+ for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
+
+ IndexedTenant tenant = ctx.getTenant(sourceEpgKey.getTenantId());
+ if (tenant != null) {
+ EndpointGroup group = tenant.getEndpointGroup(sourceEpgKey.getEgId());
+ if (group == null) {
+ LOG.debug("EPG {} does not exit and is used in EP {}", sourceEpgKey, sourceEp.getKey());
+ continue;
+ }
+ IntraGroupPolicy igp = group.getIntraGroupPolicy();
+
+ if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
+ for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(sourceEpgKey)) {
+ EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
+ OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
+ if (srcEpFwdCxtOrdinals == null) {
+ LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
+ continue;
+ }
+
+ EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
+ OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
+ if (dstEpFwdCxtOrdinals == null) {
+ LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
+ continue;
+ }
+
+ int destinationEpgId = dstEpFwdCxtOrdinals.getEpgId();
+ int sourceEpgId = srcEpFwdCxtOrdinals.getEpgId();
+ ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(sourceEpgId, destinationEpgId));
+ ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(destinationEpgId, sourceEpgId));
}
}
}
- /*
- * Convert the GBP Action to one or more OpenFlow Actions
- */
- actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements);
}
- } else {
- Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
- actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
}
+ }
+
+ // Return list of all rules with opposite direction
+ private List<Rule> findRulesInSameDirection(Rule ruleToResolve, List<Rule> reversedRules) {
+ List<Rule> sameDirectionRules = new ArrayList<>();
+ for (Rule ruleToCompare : reversedRules) {
+ for (ClassifierRef classifierRefToCompare : ruleToCompare.getClassifierRef()) {
+ for (ClassifierRef classifierRefToResolve : ruleToResolve.getClassifierRef()) {
+ if (isDirectionOpposite(classifierRefToCompare.getDirection(), classifierRefToResolve.getDirection())) {
+ sameDirectionRules.add(ruleToCompare);
+ }
+ }
+ }
+ }
+ return sameDirectionRules;
+ }
+
+ private boolean isDirectionOpposite(Direction one, Direction two) {
+ return ((one.equals(Direction.In) && two.equals(Direction.Out))
+ || (one.equals(Direction.Out) && two.equals(Direction.In)));
+ }
+
+ private List<Rule> getRules(List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules) {
+ List<Rule> rules = new ArrayList<>();
+ for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRule : activeRules) {
+ for (RuleGroup ruleGroup : activeRule.getValue()) {
+ for (Rule rule : ruleGroup.getRules()) {
+ rules.add(rule);
+ }
+ }
+ }
+ return rules;
+ }
+
+ private Flow createArpFlow(Integer fdId) {
+
+ Long etherType = FlowUtils.ARP;
+ // L2 Classifier so 20,000 for now
+ Integer priority = 20000;
+
+ MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
+
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
+
+ Match match = mb.build();
+ FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
+ return base().setPriority(priority)
+ .setId(flowid)
+ .setMatch(match)
+ .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
+ .build();
+ }
+
+ private Flow allowSameEpg(int sourceEpgId, int destinationEpgId) {
+
+ MatchBuilder mb = new MatchBuilder();
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) sourceEpgId),
+ RegMatch.of(NxmNxReg2.class, (long) destinationEpgId));
+ Match match = mb.build();
+ FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
+ FlowBuilder flow = base().setId(flowId)
+ .setMatch(match)
+ .setPriority(65000)
+ .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
+ return flow.build();
+ }
+
+ private Flow allowFromTunnel(NodeConnectorId tunPort) {
+
+ MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
+ Match match = mb.build();
+ FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
+ FlowBuilder flow = base().setId(flowId)
+ .setMatch(match)
+ .setPriority(65000)
+ .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
+ return flow.build();
+ }
+
+ private List<MatchBuilder> createMatches(Direction direction, PolicyPair policyPair, IndexedTenant contractTenant,
+ Rule rule) {
Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
Set<ClassifierDefinitionId> classifiers = new HashSet<>();
for (ClassifierRef cr : rule.getClassifierRef()) {
+
if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
&& !cr.getDirection().equals(direction)) {
continue;
// extension and data plane support - in 2.4. Will need to handle
// case where we are working with mix of nodes.
- ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
+ ClassifierInstance ci = contractTenant.getClassifier(cr.getInstanceName());
if (ci == null) {
// XXX TODO fail the match and raise an exception
- LOG.warn("Classifier instance {} not found", cr.getName().getValue());
- return;
+ LOG.warn("Classifier instance {} not found", cr.getInstanceName().getValue());
+ return null;
}
- Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
- if (cfier == null) {
+ Classifier classifier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
+ if (classifier == null) {
// XXX TODO fail the match and raise an exception
LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
- return;
+ return null;
}
classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
for (ParameterValue v : ci.getParameterValue()) {
if (paramsFromClassifier.get(v.getName().getValue()) == null) {
- if (v.getIntValue() != null
- || v.getStringValue() != null
- || v.getRangeValue() != null) {
+ if (v.getIntValue() != null || v.getStringValue() != null || v.getRangeValue() != null) {
paramsFromClassifier.put(v.getName().getValue(), v);
}
} else {
}
}
}
- if(classifiers.isEmpty()) {
- return;
+ if (classifiers.isEmpty()) {
+ return null;
}
List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
- String baseId = createBaseFlowId(direction, cgPair, priority);
List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
for (Map<String, ParameterValue> params : derivedParamsByName) {
List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
- if (cgPair.sIpPrefixes.isEmpty() && cgPair.dIpPrefixes.isEmpty()) {
- matchBuildersToResolve.add(createBaseMatch(direction, cgPair, null, null));
- } else if (!cgPair.sIpPrefixes.isEmpty() && cgPair.dIpPrefixes.isEmpty()) {
- for (IpPrefix sIpPrefix : cgPair.sIpPrefixes) {
- matchBuildersToResolve.add(createBaseMatch(direction, cgPair, sIpPrefix, null));
+ if (policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
+ matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, null));
+ } else if (!policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
+ for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
+ matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, null));
}
- } else if (cgPair.sIpPrefixes.isEmpty() && !cgPair.dIpPrefixes.isEmpty()) {
- for (IpPrefix dIpPrefix : cgPair.sIpPrefixes) {
- matchBuildersToResolve.add(createBaseMatch(direction, cgPair, null, dIpPrefix));
+ } else if (policyPair.consumerEicIpPrefixes.isEmpty() && !policyPair.providerEicIpPrefixes.isEmpty()) {
+ for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
+ matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, dIpPrefix));
}
} else {
- for (IpPrefix sIpPrefix : cgPair.sIpPrefixes) {
- for (IpPrefix dIpPrefix : cgPair.sIpPrefixes) {
- matchBuildersToResolve.add(createBaseMatch(direction, cgPair, sIpPrefix, dIpPrefix));
+ for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
+ for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
+ matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, dIpPrefix));
}
}
}
ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
if (!result.isSuccessfull()) {
// TODO consider different handling.
- throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName() + ".\nCause: "
- + result.getErrorMessage());
+ throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName()
+ + ".\nCause: " + result.getErrorMessage());
}
matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
}
flowMatchBuilders.addAll(matchBuildersToResolve);
}
- FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
- for (MatchBuilder match : flowMatchBuilders) {
- Match m = match.build();
- FlowId flowId = new FlowId(baseId + "|" + m.toString());
- flow.setMatch(m)
- .setId(flowId)
- .setPriority(Integer.valueOf(priority))
- .setInstructions(instructions(applyActionIns(actionBuilderList)));
- flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build());
+ return flowMatchBuilders;
+ }
+
+ private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction, PolicyPair policyPair,
+ IndexedTenant contractTenant, Rule rule, boolean isReversedDirection) {
+ List<ActionBuilder> actionBuilderList = new ArrayList<>();
+ if (rule.getActionRef() != null) {
+
+ // Pre-sort by references using order, then name
+ List<ActionRef> actionRefList = new ArrayList<>(rule.getActionRef());
+ Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
+
+ for (ActionRef actionRule : actionRefList) {
+ ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
+ if (actionInstance == null) {
+ // XXX TODO fail the match and raise an exception
+ LOG.warn("Action instance {} not found", actionRule.getName().getValue());
+ return null;
+ }
+ Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
+ if (action == null) {
+ // XXX TODO fail the match and raise an exception
+ LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
+ return null;
}
+
+ Map<String, Object> params = new HashMap<>();
+ if (actionInstance.getParameterValue() != null) {
+ for (ParameterValue v : actionInstance.getParameterValue()) {
+ if (v.getName() == null)
+ continue;
+ if (v.getIntValue() != null) {
+ params.put(v.getName().getValue(), v.getIntValue());
+ } else if (v.getStringValue() != null) {
+ params.put(v.getName().getValue(), v.getStringValue());
+ }
+ }
+ }
+ if (isReversedDirection) {
+ direction = reverse(direction);
+ }
+
+ // Convert the GBP Action to one or more OpenFlow Actions
+ if (!(actionRefList.indexOf(actionRule) == (actionRefList.size() - 1)
+ && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId())))) {
+ actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(), netElements,
+ policyPair, ofWriter, ctx, direction);
+ }
+ }
+ }
+
+ return actionBuilderList;
}
- private String createBaseFlowId(Direction direction, CgPair cgPair, int priority) {
- StringBuilder idb = new StringBuilder();
+ private Direction reverse(Direction direction) {
if (direction.equals(Direction.In)) {
- idb.append(cgPair.sepg)
- .append("|")
- .append(cgPair.scgId)
- .append("|")
- .append(cgPair.depg)
- .append("|")
- .append(cgPair.dcgId)
- .append("|")
- .append(priority);
- } else {
- idb.append(cgPair.depg)
- .append("|")
- .append(cgPair.dcgId)
- .append("|")
- .append(cgPair.sepg)
- .append("|")
- .append(cgPair.scgId)
- .append("|")
- .append(priority);
- }
- return idb.toString();
+ return Direction.Out;
+ }
+ else if(direction.equals(Direction.Out)) {
+ return Direction.In;
+ }
+ else {
+ return Direction.Bidirectional;
+ }
}
- private MatchBuilder createBaseMatch(Direction direction, CgPair cgPair, IpPrefix sIpPrefix, IpPrefix dIpPrefix) {
+ private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList, NetworkElements netElements,
+ OfWriter ofWriter, int priority) {
+ FlowBuilder flow = base().setPriority(priority);
+ if(flowMatchBuilders == null) {
+ return;
+ }
+ for (MatchBuilder mb : flowMatchBuilders) {
+ Match match = mb.build();
+ FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "cg", match);
+ flow.setMatch(match).setId(flowId).setPriority(priority);
+
+ // If destination is External, the last Action ALLOW must be changed to goto
+ // NAT/External table.
+ // If actionBuilderList is empty (we removed the last Allow) then go straight to
+ // ExternalMapper table.
+
+ List<ExternalImplicitGroup> eigs = ctx.getTenant(netElements.getDstEp().getTenant())
+ .getTenant()
+ .getPolicy()
+ .getExternalImplicitGroup();
+ boolean performNat = false;
+ for (EndpointL3 natEp : ctx.getEndpointManager().getL3EndpointsWithNat()) {
+ if (natEp.getMacAddress() != null &&
+ natEp.getL2Context() != null &&
+ netElements.getSrcEp().getKey().equals(new EndpointKey(natEp.getL2Context(),
+ natEp.getMacAddress())) &&
+ EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
+ performNat = true;
+ break;
+ }
+ }
+ if (actionBuilderList == null) {
+ //TODO - analyse, what happen for unknown action, SFC, etc.
+ LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
+ continue;
+ }
+ if (actionBuilderList.isEmpty()) {
+ flow.setInstructions((performNat == true) ? instructions(gotoEgressNatInstruction) : instructions(gotoExternalInstruction));
+ } else {
+ flow.setInstructions(instructions(applyActionIns(actionBuilderList),
+ (performNat == true) ? gotoEgressNatInstruction : gotoExternalInstruction));
+ }
+ ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
+ }
+ }
+
+ private MatchBuilder createBaseMatch(Direction direction, PolicyPair policyPair, IpPrefix sIpPrefix,
+ IpPrefix dIpPrefix) {
MatchBuilder baseMatch = new MatchBuilder();
if (direction.equals(Direction.In)) {
- addNxRegMatch(baseMatch,
- RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
- RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
- RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
- RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
+ addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.consumerEpgId),
+ RegMatch.of(NxmNxReg1.class, (long) policyPair.consumerCondGrpId),
+ RegMatch.of(NxmNxReg2.class, (long) policyPair.providerEpgId),
+ RegMatch.of(NxmNxReg3.class, (long) policyPair.providerCondGrpId));
if (sIpPrefix != null) {
baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
}
baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
}
} else {
- addNxRegMatch(baseMatch,
- RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
- RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
- RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
- RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
+ addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.providerEpgId),
+ RegMatch.of(NxmNxReg1.class, (long) policyPair.providerCondGrpId),
+ RegMatch.of(NxmNxReg2.class, (long) policyPair.consumerEpgId),
+ RegMatch.of(NxmNxReg3.class, (long) policyPair.consumerCondGrpId));
if (sIpPrefix != null) {
baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
}
}
// TODO: move to a common utils for all renderers
- public List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>>
- getActiveRulesBetweenEps(Policy policy, Endpoint consEp, Endpoint provEp) {
+ private List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
+ Endpoint consEp, Endpoint provEp) {
List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
- if (policy.getRuleMap() != null) {
- for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
- EndpointConstraint consEpConstraint = cell.getRowKey();
- EndpointConstraint provEpConstraint = cell.getColumnKey();
- if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
- rulesWithEpConstraints.add(cell);
- }
+ for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
+ EndpointConstraint consEpConstraint = cell.getRowKey();
+ EndpointConstraint provEpConstraint = cell.getColumnKey();
+ if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
+ rulesWithEpConstraints.add(cell);
}
}
return rulesWithEpConstraints;
return constraint.getConditionSet().matches(epConditions);
}
- @Immutable
- private static class CgPair {
+ private enum PathStatus { both, partial, none }
+
+ public static boolean checkPolicyOrientation() {
+ return isReversedPolicy;
+ }
+
+ /**
+ * Private internal class for ordering Actions in Rules. The order is
+ * determined first by the value of the order parameter, with the lower
+ * order actions being applied first; for Actions with either the same order
+ * or no order, ordering is lexicographical by name.
+ */
+ private static class ActionRefComparator implements Comparator<ActionRef> {
- private final int sepg;
- private final int depg;
- private final int scgId;
- private final int dcgId;
- private final Set<IpPrefix> sIpPrefixes;
- private final Set<IpPrefix> dIpPrefixes;
+ public static final ActionRefComparator INSTANCE = new ActionRefComparator();
- public CgPair(int sepg, int depg, int scgId, int dcgId, Set<IpPrefix> sIpPrefixes, Set<IpPrefix> dIpPrefixes) {
+ @Override
+ public int compare(ActionRef arg0, ActionRef arg1) {
+ return ComparisonChain.start()
+ .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
+ .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
+ .result();
+ }
+
+ }
+
+ @Immutable
+ public static class PolicyPair {
+
+ private final int consumerEpgId;
+ private final int providerEpgId;
+ private final int consumerCondGrpId;
+ private final int providerCondGrpId;
+ private final Set<IpPrefix> consumerEicIpPrefixes;
+ private final Set<IpPrefix> providerEicIpPrefixes;
+ private final NodeId consumerEpNodeId;
+ private final NodeId providerEpNodeId;
+
+ public PolicyPair(int consumerEpgId, int providerEpgId, int consumerCondGrpId, int providerCondGrpId,
+ Set<IpPrefix> consumerEicIpPrefixes, Set<IpPrefix> providerEicIpPrefixes, NodeId consumerEpNodeId, NodeId providerEpNodeId) {
super();
- this.sepg = sepg;
- this.depg = depg;
- this.scgId = scgId;
- this.dcgId = dcgId;
- this.sIpPrefixes = sIpPrefixes;
- this.dIpPrefixes = dIpPrefixes;
+ this.consumerEpgId = consumerEpgId;
+ this.providerEpgId = providerEpgId;
+ this.consumerCondGrpId = consumerCondGrpId;
+ this.providerCondGrpId = providerCondGrpId;
+ this.consumerEicIpPrefixes = consumerEicIpPrefixes;
+ this.providerEicIpPrefixes = providerEicIpPrefixes;
+ this.consumerEpNodeId = consumerEpNodeId;
+ this.providerEpNodeId = providerEpNodeId;
+ }
+
+ public int getConsumerEpgId() {
+ return consumerEpgId;
+ }
+
+ public int getProviderEpgId() {
+ return providerEpgId;
+ }
+
+ public NodeId getConsumerEpNodeId() {
+ return consumerEpNodeId;
+ }
+
+ public NodeId getProviderEpNodeId() {
+ return providerEpNodeId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((dIpPrefixes == null) ? 0 : dIpPrefixes.hashCode());
- result = prime * result + dcgId;
- result = prime * result + depg;
- result = prime * result + ((sIpPrefixes == null) ? 0 : sIpPrefixes.hashCode());
- result = prime * result + scgId;
- result = prime * result + sepg;
+ result = prime * result + ((providerEicIpPrefixes == null) ? 0 : providerEicIpPrefixes.hashCode());
+ result = prime * result + providerCondGrpId;
+ result = prime * result + providerEpgId;
+ result = prime * result + ((consumerEicIpPrefixes == null) ? 0 : consumerEicIpPrefixes.hashCode());
+ result = prime * result + consumerCondGrpId;
+ result = prime * result + consumerEpgId;
+ result = prime * result + ((consumerEpNodeId == null) ? 0 : consumerEpNodeId.hashCode());
+ result = prime * result + ((providerEpNodeId == null) ? 0 : providerEpNodeId.hashCode());
+
return result;
}
return false;
if (getClass() != obj.getClass())
return false;
- CgPair other = (CgPair) obj;
- if (dIpPrefixes == null) {
- if (other.dIpPrefixes != null)
+ PolicyPair other = (PolicyPair) obj;
+ if (providerEicIpPrefixes == null) {
+ if (other.providerEicIpPrefixes != null) {
return false;
- } else if (!dIpPrefixes.equals(other.dIpPrefixes))
- return false;
- if (dcgId != other.dcgId)
+ }
+ } else if (!providerEicIpPrefixes.equals(other.providerEicIpPrefixes)) {
return false;
- if (sIpPrefixes == null) {
- if (other.sIpPrefixes != null)
+ }
+ if (consumerEicIpPrefixes == null) {
+ if (other.consumerEicIpPrefixes != null) {
return false;
- } else if (!sIpPrefixes.equals(other.sIpPrefixes))
- return false;
- if (depg != other.depg)
+ }
+ } else if (!consumerEicIpPrefixes.equals(other.consumerEicIpPrefixes)) {
return false;
- if (scgId != other.scgId)
+ }
+ if (consumerEpNodeId == null) {
+ if (other.consumerEpNodeId != null) {
+ return false;
+ }
+ } else if (!consumerEpNodeId.getValue().equals(other.consumerEpNodeId.getValue())) {
return false;
- if (sepg != other.sepg)
+ }
+ if (providerEpNodeId == null) {
+ if (other.providerEpNodeId != null) {
+ return false;
+ }
+ } else if (!providerEpNodeId.getValue().equals(other.providerEpNodeId.getValue())) {
return false;
- return true;
+ }
+ return (providerCondGrpId == other.providerCondGrpId)
+ && (providerEpgId == other.providerEpgId)
+ && (consumerCondGrpId == other.consumerCondGrpId)
+ && (consumerEpgId == other.consumerEpgId);
+
+ }
+
+ @Override
+ public String toString() {
+ return "consumerEPG: " + consumerEpgId +
+ "consumerCG: " + consumerCondGrpId +
+ "providerEPG: " + providerEpgId +
+ "providerCG: " + providerCondGrpId +
+ "consumerEpNodeId: " + consumerEpNodeId +
+ "providerEpNodeId: " + providerEpNodeId +
+ "consumerEicIpPrefixes: " + consumerEicIpPrefixes +
+ "providerEicIpPrefixes: " + providerEicIpPrefixes;
}
}
public class NetworkElements {
- Endpoint src;
- Endpoint dst;
- NodeId nodeId;
- EndpointFwdCtxOrdinals srcOrds;
- EndpointFwdCtxOrdinals dstOrds;
- public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception {
- this.src=src;
- this.dst=dst;
- this.nodeId = nodeId;
- this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src);
- this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst);
+ private final Endpoint srcEp;
+ private final Endpoint dstEp;
+ private final EgKey srcEpg;
+ private final EgKey dstEpg;
+ private NodeId srcNodeId;
+ private NodeId dstNodeId;
+ private final NodeId localNodeId;
+ private EndpointFwdCtxOrdinals srcEpOrdinals;
+ private EndpointFwdCtxOrdinals dstEpOrdinals;
+
+ public NetworkElements(Endpoint srcEp, Endpoint dstEp, EgKey srcEpg, EgKey dstEpg, NodeId nodeId, OfContext ctx) throws Exception {
+ this.srcEp = srcEp;
+ this.dstEp = dstEp;
+ this.srcEpg = srcEpg;
+ this.dstEpg = dstEpg;
+ this.localNodeId = nodeId;
+ this.srcEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);
+ if (this.srcEpOrdinals == null) {
+ LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
+ return;
+ }
+ this.dstEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
+ if (this.dstEpOrdinals == null) {
+ LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
+ return;
+ }
+ if (dstEp.getAugmentation(OfOverlayContext.class) != null) {
+ this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();
+ }
+ if (srcEp.getAugmentation(OfOverlayContext.class) != null) {
+ this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();
+ }
+ }
+
+
+ public Endpoint getSrcEp() {
+ return srcEp;
}
+ public Endpoint getDstEp() {
+ return dstEp;
+ }
+
+ public EgKey getSrcEpg() {
+ return srcEpg;
+ }
- public EndpointFwdCtxOrdinals getSrcOrds() {
- return srcOrds;
+ public EgKey getDstEpg() {
+ return dstEpg;
}
+ public NodeId getSrcNodeId() {
+ return srcNodeId;
+ }
- public EndpointFwdCtxOrdinals getDstOrds() {
- return dstOrds;
+ public NodeId getDstNodeId() {
+ return dstNodeId;
}
- public Endpoint getSrc() {
- return src;
+ public NodeId getLocalNodeId() {
+ return localNodeId;
}
- public Endpoint getDst() {
- return dst;
+ public EndpointFwdCtxOrdinals getSrcEpOrdinals() {
+ return srcEpOrdinals;
}
- public NodeId getNodeId() {
- return nodeId;
+ public EndpointFwdCtxOrdinals getDstEpOrdinals() {
+ return dstEpOrdinals;
}