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.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup.IntraGroupPolicy;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
87 import org.slf4j.Logger;
88 import org.slf4j.LoggerFactory;
90 import com.google.common.collect.ArrayListMultimap;
91 import com.google.common.collect.ComparisonChain;
92 import com.google.common.collect.ListMultimap;
93 import com.google.common.collect.Ordering;
94 import com.google.common.collect.Table.Cell;
97 * <h1>Manage the table that enforces policy on the traffic. Traffic is denied
98 * unless specifically allowed by policy (table=4)</h1>
100 * In policy enforcer, according to current {@link Policy} specific traffic is sent to SFC (nsp and nsi is set), or from SFC
101 * to some {@link Endpoint} or to another classifier.
103 * <i>Tunnel/overlay flows</i><br>
104 * Priority = 65000 (if more flows, decrements)<br>
106 * - ethertype (tcp, tcp6, ipv6, icmp or missing)<br>
107 * - Reg0 {@link NxmNxReg0}<br>
108 * - Reg1 {@link NxmNxReg1}<br>
109 * - Reg2 {@link NxmNxReg2}<br>
110 * - Reg3 {@link NxmNxReg3}<br>
111 * - L3 for src_ip_prefix (if exists)<br>
112 * - L3 for dst_ip_prefix (if exists)<br>
114 * - set nsi (only chain action)<br>
115 * - set nsp (only chain action)<br>
116 * - {@link GoToTable} EXTERNAL MAPPER table<br>
118 * <i>Allow from tunnel flow</i><br>
119 * Priority = 65000<br>
121 * - Reg1 (set to 0xffffff) {@link NxmNxReg1}<br>
122 * - in_port (should be tunnel port) {@link NodeConnectorId}<br>
124 * - output:port (Reg7) {@link NxmNxReg7}<br>
126 * Traffic is sent from one {@link EndpointGroup} to the same EPG
128 * <i>Allow from same EPG flow</i><br>
129 * Priority = 65000<br>
131 * - Reg0 {@link NxmNxReg0}<br>
132 * - Reg2 {@link NxmNxReg2}<br>
134 * - output:port (Reg7) {@link NxmNxReg7}
136 * <i>Arp flow</i><br>
137 * Priority = 20000<br>
139 * - ethernet match (arp)<br>
140 * - Reg5 {@link NxmNxReg5}<br>
142 * - output:port (Reg7) {@link NxmNxReg7}
145 public class PolicyEnforcer extends FlowTable {
147 private static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
148 public static short TABLE_ID;
149 private static boolean isReversedPolicy;
150 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoEgressNatInstruction;
151 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction gotoExternalInstruction;
152 private HashSet<PolicyPair> visitedPairs = new HashSet<>();
153 private HashSet<PolicyPair> visitedReversePairs = new HashSet<>();
154 private List<Rule> reversedActiveRules = new ArrayList<>();
155 private ListMultimap<EgKey, EgKey> resolvedEpgPairs = ArrayListMultimap.create();
156 private boolean directPathFlowsCreated = false;
157 private boolean reversePathFlowsCreated = false;
159 public PolicyEnforcer(OfContext ctx, short tableId) {
162 isReversedPolicy = false;
163 gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
164 gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER());
167 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoEgressNatInstruction() {
168 return gotoEgressNatInstruction;
171 private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction getGotoExternalInstruction() {
172 return gotoExternalInstruction;
176 public short getTableId() {
181 public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
183 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
185 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
186 if (tunPort != null) {
187 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
190 visitedPairs = new HashSet<>();
191 reversedActiveRules = new ArrayList<>();
192 visitedReversePairs = new HashSet<>();
193 resolvedEpgPairs = ArrayListMultimap.create();
195 // Used for ARP flows
196 Set<Integer> fdIds = new HashSet<>();
198 for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
199 for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
200 Set<EgKey> peers = ctx.getCurrentPolicy().getPeers(sourceEpgKey);
201 for (EgKey destinationEpgKey : peers) {
203 Set<Endpoint> destinationEndpoints = new HashSet<>();
204 destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(destinationEpgKey));
205 destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(destinationEpgKey));
206 for (Endpoint destinationEp : destinationEndpoints) {
208 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
209 if (srcEpFwdCxtOrdinals == null) {
210 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", sourceEp);
214 EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEp);
215 if (dstEpFwdCxtOrdinals == null) {
216 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEp);
220 fdIds.add(srcEpFwdCxtOrdinals.getFdId());
221 NetworkElements netElements = new NetworkElements(sourceEp, destinationEp, sourceEpgKey,
222 destinationEpgKey, nodeId, ctx);
224 // Get policy in both directions
225 Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destinationEpgKey, sourceEpgKey);
226 Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpgKey, destinationEpgKey);
227 reversedActiveRules = getRules(getActiveRulesBetweenEps(destinationEpgPolicy, sourceEp, destinationEp));
229 // Resolve flows in both directions if possible according to policy. Get back status of resolution
230 PathStatus status = resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy);
232 // When source Epg policy creates no flows, destination Epg policy has to be resolved
233 if (status.equals(PathStatus.none)) {
234 resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, false);
236 // When source Epg policy creates flows only in one direction, the other direction has to be
237 // created here. Is essential to revert directions to prevent flow overriding and incorrect nsp
239 else if (status.equals(PathStatus.partial)) {
240 resolveDestinationEpgPolicy(ofWriter, netElements, destinationEpgPolicy, true);
248 allowSameEpg(nodeId, ofWriter);
250 // Write ARP flows per flood domain
251 for (Integer fdId : fdIds) {
252 ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
256 private PathStatus resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy) {
257 isReversedPolicy = false;
258 directPathFlowsCreated = false;
259 reversePathFlowsCreated = false;
261 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
262 directPolicy, netElements.getDstEp(), netElements.getSrcEp())) {
263 Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
265 Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
268 int priority = 65000;
269 for (RuleGroup rg : activeRulesByConstraints.getValue()) {
270 TenantId tenantId = rg.getContractTenant().getId();
271 IndexedTenant tenant = ctx.getTenant(tenantId);
272 for (Rule rule : rg.getRules()) {
274 // Find all rules in the same traffic direction
275 List<Rule> sameDirectionRules = findRulesInSameDirection(rule, reversedActiveRules);
276 if (sameDirectionRules.isEmpty()) {
277 sameDirectionRules.add(rule);
279 sameDirectionRules = Ordering.from(TenantUtils.RULE_COMPARATOR)
280 .immutableSortedCopy(sameDirectionRules);
282 // Create flows for every pair of rules
283 for (Rule oppositeRule : sameDirectionRules) {
285 // Evaluate which rule has more specific matches
286 Rule ruleWithMatches = findRuleWithSpecificMatches(rule, oppositeRule, tenant);
287 Rule ruleWithActions = mergeRuleActions(rule, oppositeRule, tenant);
288 if (ruleWithMatches == null) {
289 LOG.trace("No matches found for pair of rules {}, {}", rule, oppositeRule);
292 if (ruleWithActions == null) {
293 LOG.trace("No actions found for pair of rules {}, {}", rule, oppositeRule);
296 PolicyPair policyPair = null;
297 if (rule.equals(ruleWithMatches)) {
298 policyPair = new PolicyPair(netElements.getDstEpOrdinals().getEpgId(),
299 netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getCgId(),
300 netElements.getSrcEpOrdinals().getCgId(), dIpPrefixes, sIpPrefixes,
301 netElements.getDstNodeId(), netElements.getSrcNodeId());
303 policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(),
304 netElements.getDstEpOrdinals().getEpgId(), netElements.getSrcEpOrdinals().getCgId(),
305 netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
306 netElements.getSrcNodeId(), netElements.getDstNodeId());
308 LOG.trace("PolicyEnforcer: Visiting PolicyPair {} endpoints {} {}", policyPair,
309 netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
311 // Preserve original rule direction
312 Set<Direction> directions = getRuleDirections(rule);
314 for(Direction direction : directions) {
316 // Create list of matches/actions. Also creates chain flows when specific action requires it
317 List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant,
319 List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant,
322 List<ActionBuilder> actions = createActions(ofWriter, netElements, direction,
323 policyPair, tenant, ruleWithActions, false);
326 createFlows(inMatches, actions, netElements, ofWriter, priority);
327 createFlows(outMatches, actions, netElements, ofWriter, priority);
331 // Keep info about what direction has flows already created
332 if (direction.equals(Direction.In)) {
333 directPathFlowsCreated = true;
335 if (direction.equals(Direction.Out)) {
336 reversePathFlowsCreated = true;
339 // Fully resolved Ep groups are saved to prevent duplicates
340 if (directPathFlowsCreated && reversePathFlowsCreated) {
341 LOG.trace("Epg pair added: {}, {} ", netElements.getSrcEpg(), netElements.getDstEpg());
342 resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
350 // Returns appropriate result of resolving
351 if (directPathFlowsCreated && reversePathFlowsCreated) {
352 return PathStatus.both;
353 } else if ((!directPathFlowsCreated && reversePathFlowsCreated) || (directPathFlowsCreated && !reversePathFlowsCreated)) {
354 return PathStatus.partial;
356 return PathStatus.none;
360 private Set<Direction> getRuleDirections(Rule ruleWithMatches) {
361 Set<Direction> directions = new HashSet<>();
362 for (ClassifierRef classifierRef : ruleWithMatches.getClassifierRef()) {
363 if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.In) {
364 directions.add(classifierRef.getDirection());
366 if (!directions.contains(classifierRef.getDirection()) && classifierRef.getDirection() == Direction.Out) {
367 directions.add(classifierRef.getDirection());
370 if (directions.isEmpty()) {
371 directions.add(Direction.Bidirectional);
376 private Rule mergeRuleActions(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
377 if (oppositeRule.equals(rule)) {
381 Action ruleAction = null;
382 Action oppositeRuleAction = null;
384 // For now, only allow action and chain action is supported
385 for (ActionRef actionRef : rule.getActionRef()) {
386 ActionInstance actionInstance = tenant.getAction(actionRef.getName());
387 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
388 ruleAction = new AllowAction();
390 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
391 ruleAction = new ChainAction();
394 for (ActionRef actionRef : oppositeRule.getActionRef()) {
395 ActionInstance actionInstance = tenant.getAction(actionRef.getName());
396 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new AllowAction().getId()))) {
397 oppositeRuleAction = new AllowAction();
399 if (actionRef.getOrder() == 0 && (actionInstance.getActionDefinitionId().equals(new ChainAction().getId()))) {
400 oppositeRuleAction = new ChainAction();
404 if (ruleAction == null && oppositeRuleAction == null) {
406 } else if (ruleAction != null && ruleAction.getClass().equals(AllowAction.class)) {
408 } else if (oppositeRuleAction != null && oppositeRuleAction.getClass().equals(AllowAction.class)) {
411 // TODO both rules have chain action - add support for more different chain actions. This works for now
416 private Rule findRuleWithSpecificMatches(Rule rule, Rule oppositeRule, IndexedTenant tenant) {
417 if (oppositeRule.equals(rule)) {
421 // TODO check all classifierRefs
422 ClassifierRef ruleClassifierRef = rule.getClassifierRef().get(0);
423 ClassifierRef oppositeRuleClassifierRef = oppositeRule.getClassifierRef().get(0);
425 ClassifierInstance ruleClassifierInstance = tenant.getClassifier(ruleClassifierRef.getInstanceName());
426 ClassifierInstance oppositeRuleClassifierInstance = tenant.getClassifier(oppositeRuleClassifierRef.getInstanceName());
428 if (ruleClassifierInstance == null) {
429 LOG.trace("Classifier instance not found, ClassifierRef name: {} ", ruleClassifierRef.getInstanceName());
432 if (oppositeRuleClassifierInstance == null) {
433 LOG.trace("Opposite classifier instance not found, ClassifierRef name: {} ", oppositeRuleClassifierRef.getInstanceName());
437 // Check ethertype. Values must be equal
438 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
439 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
440 if ((ruleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
441 && oppositeRuleParameter.getName().getValue().equals(EtherTypeClassifierDefinition.ETHERTYPE_PARAM)) {
442 if (!ruleParameter.getIntValue().equals(oppositeRuleParameter.getIntValue())) {
443 LOG.trace("Ethertype values are not equal, rule: {}, opposite rule: {} ", rule, oppositeRule);
449 // Check proto if exists. Values must be equal or missing
450 ParameterValue ruleProtoParameter = null;
451 ParameterValue oppositeRuleProtoParameter = null;
452 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
453 if (ruleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
454 ruleProtoParameter = ruleParameter;
457 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
458 if (oppositeRuleParameter.getName().getValue().equals(IpProtoClassifierDefinition.PROTO_PARAM)) {
459 oppositeRuleProtoParameter = oppositeRuleParameter;
463 if (ruleProtoParameter == null || ruleProtoParameter.getIntValue() == null) {
465 } else if (oppositeRuleProtoParameter == null || oppositeRuleProtoParameter.getIntValue() == null) {
467 } else if (!ruleProtoParameter.getIntValue().equals(oppositeRuleProtoParameter.getIntValue())) {
468 LOG.trace("Proto parameters are not equal, rule parameters: {}, opposite rule parameters {} ",
469 ruleProtoParameter, oppositeRuleProtoParameter);
474 // TODO add support for port ranges
475 ParameterValue ruleL4Src = null;
476 ParameterValue oppositeRuleL4Src = null;
477 ParameterValue ruleL4Dst = null;
478 ParameterValue oppositeRuleL4Dst = null;
480 for (ParameterValue ruleParameter : ruleClassifierInstance.getParameterValue()) {
481 if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
482 ruleL4Src = ruleParameter;
484 if (ruleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
485 ruleL4Dst = ruleParameter;
488 for (ParameterValue oppositeRuleParameter : oppositeRuleClassifierInstance.getParameterValue()) {
489 if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.SRC_PORT_PARAM)) {
490 oppositeRuleL4Src = oppositeRuleParameter;
492 if (oppositeRuleParameter.getName().getValue().equals(L4ClassifierDefinition.DST_PORT_PARAM)) {
493 oppositeRuleL4Dst = oppositeRuleParameter;
497 if (ruleL4Src == null && ruleL4Dst == null && oppositeRuleL4Src == null && oppositeRuleL4Dst == null) {
502 if (ruleL4Src == null && oppositeRuleL4Src != null) {
505 if (ruleL4Src != null && oppositeRuleL4Src == null) {
508 if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
509 && ruleL4Src.equals(oppositeRuleL4Src)) {
512 if (ruleL4Src != null && ruleL4Src.getIntValue() != null && oppositeRuleL4Src.getIntValue() != null
513 && !ruleL4Src.equals(oppositeRuleL4Src)) {
518 if (ruleL4Dst == null && oppositeRuleL4Dst != null) {
521 if (ruleL4Dst != null && oppositeRuleL4Dst == null) {
524 if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
525 && ruleL4Dst.equals(oppositeRuleL4Dst)) {
528 if (ruleL4Dst != null && ruleL4Dst.getIntValue() != null && oppositeRuleL4Dst.getIntValue() != null
529 && !ruleL4Dst.equals(oppositeRuleL4Dst)) {
536 private void resolveDestinationEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy reversedPolicy,
537 boolean isReverted) {
538 isReversedPolicy = true;
539 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : getActiveRulesBetweenEps(
540 reversedPolicy, netElements.getSrcEp(), netElements.getDstEp())) {
541 Set<IpPrefix> sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey()
543 Set<IpPrefix> dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey()
545 PolicyPair policyPair = new PolicyPair(netElements.getSrcEpOrdinals().getEpgId(), netElements.getDstEpOrdinals().getEpgId(),
546 netElements.getSrcEpOrdinals().getCgId(), netElements.getDstEpOrdinals().getCgId(), sIpPrefixes, dIpPrefixes,
547 netElements.getSrcNodeId(), netElements.getDstNodeId());
548 if (visitedReversePairs.contains(policyPair)) {
550 "PolicyEnforcer: Reverse: Already visited PolicyPair {}, endpoints {} {} skipped",
551 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
554 LOG.trace("PolicyEnforcer: Reverse: Visiting: PolicyPair {} via endpoints {} {}",
555 policyPair, netElements.getSrcEp().getKey(), netElements.getDstEp().getKey());
556 visitedReversePairs.add(policyPair);
559 int priority = 65000;
560 for (RuleGroup rg : activeRulesByConstraints.getValue()) {
561 TenantId tenantId = rg.getContractTenant().getId();
562 IndexedTenant tenant = ctx.getTenant(tenantId);
563 for (Rule rule : rg.getRules()) {
565 Set<Direction> directions = getRuleDirections(rule);
566 if (directions.isEmpty()) {
570 for(Direction direction : directions) {
572 // When specific direction flows exists, do not create them again
573 if (direction.equals(Direction.In) && reversePathFlowsCreated) {
576 if (direction.equals(Direction.Out) && directPathFlowsCreated) {
580 List<MatchBuilder> inMatches = createMatches(Direction.In, policyPair, tenant, rule);
581 List<MatchBuilder> outMatches = createMatches(Direction.Out, policyPair, tenant, rule);
583 // In case chain action is called here, it has to know that this is reversed policy to set tunnel
585 List<ActionBuilder> inActions = createActions(ofWriter, netElements, Direction.In, policyPair, tenant,
587 List<ActionBuilder> outActions = createActions(ofWriter, netElements, Direction.Out, policyPair, tenant,
590 createFlows(inMatches, inActions, netElements, ofWriter, priority);
591 createFlows(outMatches, outActions, netElements, ofWriter, priority);
593 if (direction.equals(Direction.In)) {
594 reversePathFlowsCreated = true;
596 if (direction.equals(Direction.Out)) {
597 directPathFlowsCreated = true;
602 if (directPathFlowsCreated && reversePathFlowsCreated) {
603 resolvedEpgPairs.put(netElements.getSrcEpg(), netElements.getDstEpg());
611 private void allowSameEpg(NodeId nodeId, OfWriter ofWriter) throws Exception {
612 for (Endpoint sourceEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
613 for (EgKey sourceEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(sourceEp)) {
615 IndexedTenant tenant = ctx.getTenant(sourceEpgKey.getTenantId());
616 if (tenant != null) {
617 EndpointGroup group = tenant.getEndpointGroup(sourceEpgKey.getEgId());
619 LOG.debug("EPG {} does not exit and is used in EP {}", sourceEpgKey, sourceEp.getKey());
622 IntraGroupPolicy igp = group.getIntraGroupPolicy();
624 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
625 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(sourceEpgKey)) {
626 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
627 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
628 if (srcEpFwdCxtOrdinals == null) {
629 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
633 EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
634 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
635 if (dstEpFwdCxtOrdinals == null) {
636 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
640 int destinationEpgId = dstEpFwdCxtOrdinals.getEpgId();
641 int sourceEpgId = srcEpFwdCxtOrdinals.getEpgId();
642 ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(sourceEpgId, destinationEpgId));
643 ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(destinationEpgId, sourceEpgId));
651 // Return list of all rules with opposite direction
652 private List<Rule> findRulesInSameDirection(Rule ruleToResolve, List<Rule> reversedRules) {
653 List<Rule> sameDirectionRules = new ArrayList<>();
654 for (Rule ruleToCompare : reversedRules) {
655 for (ClassifierRef classifierRefToCompare : ruleToCompare.getClassifierRef()) {
656 for (ClassifierRef classifierRefToResolve : ruleToResolve.getClassifierRef()) {
657 if (isDirectionOpposite(classifierRefToCompare.getDirection(), classifierRefToResolve.getDirection())) {
658 sameDirectionRules.add(ruleToCompare);
663 return sameDirectionRules;
666 private boolean isDirectionOpposite(Direction one, Direction two) {
667 return ((one.equals(Direction.In) && two.equals(Direction.Out))
668 || (one.equals(Direction.Out) && two.equals(Direction.In)));
671 private List<Rule> getRules(List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules) {
672 List<Rule> rules = new ArrayList<>();
673 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRule : activeRules) {
674 for (RuleGroup ruleGroup : activeRule.getValue()) {
675 for (Rule rule : ruleGroup.getRules()) {
683 private Flow createArpFlow(Integer fdId) {
685 Long etherType = FlowUtils.ARP;
686 // L2 Classifier so 20,000 for now
687 Integer priority = 20000;
689 MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
691 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
693 Match match = mb.build();
694 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
695 return base().setPriority(priority)
698 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
702 private Flow allowSameEpg(int sourceEpgId, int destinationEpgId) {
704 MatchBuilder mb = new MatchBuilder();
705 addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) sourceEpgId),
706 RegMatch.of(NxmNxReg2.class, (long) destinationEpgId));
707 Match match = mb.build();
708 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
709 FlowBuilder flow = base().setId(flowId)
712 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
716 private Flow allowFromTunnel(NodeConnectorId tunPort) {
718 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
719 addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
720 Match match = mb.build();
721 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
722 FlowBuilder flow = base().setId(flowId)
725 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
730 private List<MatchBuilder> createMatches(Direction direction, PolicyPair policyPair, IndexedTenant contractTenant,
732 Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
733 Set<ClassifierDefinitionId> classifiers = new HashSet<>();
734 for (ClassifierRef cr : rule.getClassifierRef()) {
736 if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
737 && !cr.getDirection().equals(direction)) {
741 // XXX - TODO - implement connection tracking (requires openflow
742 // extension and data plane support - in 2.4. Will need to handle
743 // case where we are working with mix of nodes.
745 ClassifierInstance ci = contractTenant.getClassifier(cr.getInstanceName());
747 // XXX TODO fail the match and raise an exception
748 LOG.warn("Classifier instance {} not found", cr.getInstanceName().getValue());
751 Classifier classifier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
752 if (classifier == null) {
753 // XXX TODO fail the match and raise an exception
754 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
757 classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
758 for (ParameterValue v : ci.getParameterValue()) {
759 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
760 if (v.getIntValue() != null || v.getStringValue() != null || v.getRangeValue() != null) {
761 paramsFromClassifier.put(v.getName().getValue(), v);
764 if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
765 throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
766 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
771 if (classifiers.isEmpty()) {
774 List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
775 List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
776 for (Map<String, ParameterValue> params : derivedParamsByName) {
777 List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
778 if (policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
779 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, null));
780 } else if (!policyPair.consumerEicIpPrefixes.isEmpty() && policyPair.providerEicIpPrefixes.isEmpty()) {
781 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
782 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, null));
784 } else if (policyPair.consumerEicIpPrefixes.isEmpty() && !policyPair.providerEicIpPrefixes.isEmpty()) {
785 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
786 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, null, dIpPrefix));
789 for (IpPrefix sIpPrefix : policyPair.consumerEicIpPrefixes) {
790 for (IpPrefix dIpPrefix : policyPair.consumerEicIpPrefixes) {
791 matchBuildersToResolve.add(createBaseMatch(direction, policyPair, sIpPrefix, dIpPrefix));
795 for (ClassifierDefinitionId clDefId : classifiers) {
796 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
797 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
798 if (!result.isSuccessfull()) {
799 // TODO consider different handling.
800 throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName()
801 + ".\nCause: " + result.getErrorMessage());
803 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
805 flowMatchBuilders.addAll(matchBuildersToResolve);
807 return flowMatchBuilders;
810 private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction, PolicyPair policyPair,
811 IndexedTenant contractTenant, Rule rule, boolean isReversedDirection) {
812 List<ActionBuilder> actionBuilderList = new ArrayList<>();
813 if (rule.getActionRef() != null) {
815 // Pre-sort by references using order, then name
816 List<ActionRef> actionRefList = new ArrayList<>(rule.getActionRef());
817 Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
819 for (ActionRef actionRule : actionRefList) {
820 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
821 if (actionInstance == null) {
822 // XXX TODO fail the match and raise an exception
823 LOG.warn("Action instance {} not found", actionRule.getName().getValue());
826 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
827 if (action == null) {
828 // XXX TODO fail the match and raise an exception
829 LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
833 Map<String, Object> params = new HashMap<>();
834 if (actionInstance.getParameterValue() != null) {
835 for (ParameterValue v : actionInstance.getParameterValue()) {
836 if (v.getName() == null)
838 if (v.getIntValue() != null) {
839 params.put(v.getName().getValue(), v.getIntValue());
840 } else if (v.getStringValue() != null) {
841 params.put(v.getName().getValue(), v.getStringValue());
845 if (isReversedDirection) {
846 direction = reverse(direction);
849 // Convert the GBP Action to one or more OpenFlow Actions
850 if (!(actionRefList.indexOf(actionRule) == (actionRefList.size() - 1)
851 && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId())))) {
852 actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(), netElements,
853 policyPair, ofWriter, ctx, direction);
858 return actionBuilderList;
861 private Direction reverse(Direction direction) {
862 if (direction.equals(Direction.In)) {
863 return Direction.Out;
865 else if(direction.equals(Direction.Out)) {
869 return Direction.Bidirectional;
873 private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList, NetworkElements netElements,
874 OfWriter ofWriter, int priority) {
875 FlowBuilder flow = base().setPriority(priority);
876 if(flowMatchBuilders == null) {
879 for (MatchBuilder mb : flowMatchBuilders) {
880 Match match = mb.build();
881 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "cg", match);
882 flow.setMatch(match).setId(flowId).setPriority(priority);
884 // If destination is External, the last Action ALLOW must be changed to goto
885 // NAT/External table.
886 // If actionBuilderList is empty (we removed the last Allow) then go straight to
887 // ExternalMapper table.
889 List<ExternalImplicitGroup> eigs = ctx.getTenant(netElements.getDstEp().getTenant())
892 .getExternalImplicitGroup();
893 boolean performNat = false;
894 for (EndpointL3 natEp : ctx.getEndpointManager().getL3EndpointsWithNat()) {
895 if (natEp.getMacAddress() != null &&
896 natEp.getL2Context() != null &&
897 netElements.getSrcEp().getKey().equals(new EndpointKey(natEp.getL2Context(),
898 natEp.getMacAddress())) &&
899 EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
904 if (actionBuilderList == null) {
905 //TODO - analyse, what happen for unknown action, SFC, etc.
906 LOG.warn("Action builder list not found, partially flow which is not created: {}", flow.build());
909 if (actionBuilderList.isEmpty()) {
910 flow.setInstructions((performNat == true) ? instructions(gotoEgressNatInstruction) : instructions(gotoExternalInstruction));
912 flow.setInstructions(instructions(applyActionIns(actionBuilderList),
913 (performNat == true) ? gotoEgressNatInstruction : gotoExternalInstruction));
915 ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
919 private MatchBuilder createBaseMatch(Direction direction, PolicyPair policyPair, IpPrefix sIpPrefix,
920 IpPrefix dIpPrefix) {
921 MatchBuilder baseMatch = new MatchBuilder();
922 if (direction.equals(Direction.In)) {
923 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.consumerEpgId),
924 RegMatch.of(NxmNxReg1.class, (long) policyPair.consumerCondGrpId),
925 RegMatch.of(NxmNxReg2.class, (long) policyPair.providerEpgId),
926 RegMatch.of(NxmNxReg3.class, (long) policyPair.providerCondGrpId));
927 if (sIpPrefix != null) {
928 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
930 if (dIpPrefix != null) {
931 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
934 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) policyPair.providerEpgId),
935 RegMatch.of(NxmNxReg1.class, (long) policyPair.providerCondGrpId),
936 RegMatch.of(NxmNxReg2.class, (long) policyPair.consumerEpgId),
937 RegMatch.of(NxmNxReg3.class, (long) policyPair.consumerCondGrpId));
938 if (sIpPrefix != null) {
939 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
941 if (dIpPrefix != null) {
942 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
948 private Layer3Match createLayer3Match(IpPrefix ipPrefix, boolean isSrc) {
949 if (ipPrefix.getIpv4Prefix() != null) {
951 return new Ipv4MatchBuilder().setIpv4Source(ipPrefix.getIpv4Prefix()).build();
953 return new Ipv4MatchBuilder().setIpv4Destination(ipPrefix.getIpv4Prefix()).build();
957 return new Ipv6MatchBuilder().setIpv6Source(ipPrefix.getIpv6Prefix()).build();
959 return new Ipv6MatchBuilder().setIpv6Destination(ipPrefix.getIpv6Prefix()).build();
964 // TODO: move to a common utils for all renderers
965 private List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
966 Endpoint consEp, Endpoint provEp) {
967 List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
968 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
969 EndpointConstraint consEpConstraint = cell.getRowKey();
970 EndpointConstraint provEpConstraint = cell.getColumnKey();
971 if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
972 rulesWithEpConstraints.add(cell);
975 return rulesWithEpConstraints;
978 private boolean epMatchesConstraint(Endpoint ep, EndpointConstraint constraint) {
979 List<ConditionName> epConditions = Collections.emptyList();
980 if (ep.getCondition() != null) {
981 epConditions = ep.getCondition();
983 return constraint.getConditionSet().matches(epConditions);
986 private enum PathStatus { both, partial, none }
988 public static boolean checkPolicyOrientation() {
989 return isReversedPolicy;
993 * Private internal class for ordering Actions in Rules. The order is
994 * determined first by the value of the order parameter, with the lower
995 * order actions being applied first; for Actions with either the same order
996 * or no order, ordering is lexicographical by name.
998 private static class ActionRefComparator implements Comparator<ActionRef> {
1000 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
1003 public int compare(ActionRef arg0, ActionRef arg1) {
1004 return ComparisonChain.start()
1005 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
1006 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
1013 public static class PolicyPair {
1015 private final int consumerEpgId;
1016 private final int providerEpgId;
1017 private final int consumerCondGrpId;
1018 private final int providerCondGrpId;
1019 private final Set<IpPrefix> consumerEicIpPrefixes;
1020 private final Set<IpPrefix> providerEicIpPrefixes;
1021 private final NodeId consumerEpNodeId;
1022 private final NodeId providerEpNodeId;
1024 public PolicyPair(int consumerEpgId, int providerEpgId, int consumerCondGrpId, int providerCondGrpId,
1025 Set<IpPrefix> consumerEicIpPrefixes, Set<IpPrefix> providerEicIpPrefixes, NodeId consumerEpNodeId, NodeId providerEpNodeId) {
1027 this.consumerEpgId = consumerEpgId;
1028 this.providerEpgId = providerEpgId;
1029 this.consumerCondGrpId = consumerCondGrpId;
1030 this.providerCondGrpId = providerCondGrpId;
1031 this.consumerEicIpPrefixes = consumerEicIpPrefixes;
1032 this.providerEicIpPrefixes = providerEicIpPrefixes;
1033 this.consumerEpNodeId = consumerEpNodeId;
1034 this.providerEpNodeId = providerEpNodeId;
1037 public int getConsumerEpgId() {
1038 return consumerEpgId;
1041 public int getProviderEpgId() {
1042 return providerEpgId;
1045 public NodeId getConsumerEpNodeId() {
1046 return consumerEpNodeId;
1049 public NodeId getProviderEpNodeId() {
1050 return providerEpNodeId;
1054 public int hashCode() {
1055 final int prime = 31;
1057 result = prime * result + ((providerEicIpPrefixes == null) ? 0 : providerEicIpPrefixes.hashCode());
1058 result = prime * result + providerCondGrpId;
1059 result = prime * result + providerEpgId;
1060 result = prime * result + ((consumerEicIpPrefixes == null) ? 0 : consumerEicIpPrefixes.hashCode());
1061 result = prime * result + consumerCondGrpId;
1062 result = prime * result + consumerEpgId;
1063 result = prime * result + ((consumerEpNodeId == null) ? 0 : consumerEpNodeId.hashCode());
1064 result = prime * result + ((providerEpNodeId == null) ? 0 : providerEpNodeId.hashCode());
1070 public boolean equals(Object obj) {
1075 if (getClass() != obj.getClass())
1077 PolicyPair other = (PolicyPair) obj;
1078 if (providerEicIpPrefixes == null) {
1079 if (other.providerEicIpPrefixes != null) {
1082 } else if (!providerEicIpPrefixes.equals(other.providerEicIpPrefixes)) {
1085 if (consumerEicIpPrefixes == null) {
1086 if (other.consumerEicIpPrefixes != null) {
1089 } else if (!consumerEicIpPrefixes.equals(other.consumerEicIpPrefixes)) {
1092 if (consumerEpNodeId == null) {
1093 if (other.consumerEpNodeId != null) {
1096 } else if (!consumerEpNodeId.getValue().equals(other.consumerEpNodeId.getValue())) {
1099 if (providerEpNodeId == null) {
1100 if (other.providerEpNodeId != null) {
1103 } else if (!providerEpNodeId.getValue().equals(other.providerEpNodeId.getValue())) {
1106 return (providerCondGrpId == other.providerCondGrpId)
1107 && (providerEpgId == other.providerEpgId)
1108 && (consumerCondGrpId == other.consumerCondGrpId)
1109 && (consumerEpgId == other.consumerEpgId);
1114 public String toString() {
1115 return "consumerEPG: " + consumerEpgId +
1116 "consumerCG: " + consumerCondGrpId +
1117 "providerEPG: " + providerEpgId +
1118 "providerCG: " + providerCondGrpId +
1119 "consumerEpNodeId: " + consumerEpNodeId +
1120 "providerEpNodeId: " + providerEpNodeId +
1121 "consumerEicIpPrefixes: " + consumerEicIpPrefixes +
1122 "providerEicIpPrefixes: " + providerEicIpPrefixes;
1126 public class NetworkElements {
1128 private final Endpoint srcEp;
1129 private final Endpoint dstEp;
1130 private final EgKey srcEpg;
1131 private final EgKey dstEpg;
1132 private NodeId srcNodeId;
1133 private NodeId dstNodeId;
1134 private final NodeId localNodeId;
1135 private EndpointFwdCtxOrdinals srcEpOrdinals;
1136 private EndpointFwdCtxOrdinals dstEpOrdinals;
1138 public NetworkElements(Endpoint srcEp, Endpoint dstEp, EgKey srcEpg, EgKey dstEpg, NodeId nodeId, OfContext ctx) throws Exception {
1141 this.srcEpg = srcEpg;
1142 this.dstEpg = dstEpg;
1143 this.localNodeId = nodeId;
1144 this.srcEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);
1145 if (this.srcEpOrdinals == null) {
1146 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
1149 this.dstEpOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, dstEp);
1150 if (this.dstEpOrdinals == null) {
1151 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", dstEp);
1154 if (dstEp.getAugmentation(OfOverlayContext.class) != null) {
1155 this.dstNodeId = dstEp.getAugmentation(OfOverlayContext.class).getNodeId();
1157 if (srcEp.getAugmentation(OfOverlayContext.class) != null) {
1158 this.srcNodeId = srcEp.getAugmentation(OfOverlayContext.class).getNodeId();
1163 public Endpoint getSrcEp() {
1168 public Endpoint getDstEp() {
1172 public EgKey getSrcEpg() {
1176 public EgKey getDstEpg() {
1180 public NodeId getSrcNodeId() {
1185 public NodeId getDstNodeId() {
1190 public NodeId getLocalNodeId() {
1195 public EndpointFwdCtxOrdinals getSrcEpOrdinals() {
1196 return srcEpOrdinals;
1200 public EndpointFwdCtxOrdinals getDstEpOrdinals() {
1201 return dstEpOrdinals;