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.mapper.policyenforcer;
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.Collection;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
27 import org.opendaylight.groupbasedpolicy.api.sf.AllowActionDefinition;
28 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
29 import org.opendaylight.groupbasedpolicy.dto.EgKey;
30 import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint;
31 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
32 import org.opendaylight.groupbasedpolicy.dto.Policy;
33 import org.opendaylight.groupbasedpolicy.dto.RuleGroup;
34 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
35 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowIdUtils;
38 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable;
39 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
40 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
41 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory;
42 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
43 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
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.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
51 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup.IntraGroupPolicy;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
92 import com.google.common.base.Preconditions;
93 import com.google.common.collect.ComparisonChain;
94 import com.google.common.collect.Ordering;
95 import com.google.common.collect.Table.Cell;
98 * <h1>Manage the table that enforces policy on the traffic. Traffic is denied
99 * 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
101 * nsi is set), or from SFC
102 * to some {@link Endpoint} or to another classifier.
104 * <i>Tunnel/overlay flows</i><br>
105 * Priority = 65000 (if more flows, decrements)<br>
107 * - ethertype (tcp, tcp6, ipv6, icmp or missing)<br>
108 * - Reg0 {@link NxmNxReg0}<br>
109 * - Reg1 {@link NxmNxReg1}<br>
110 * - Reg2 {@link NxmNxReg2}<br>
111 * - Reg3 {@link NxmNxReg3}<br>
112 * - L3 for src_ip_prefix (if exists)<br>
113 * - L3 for dst_ip_prefix (if exists)<br>
115 * - set nsi (only chain action)<br>
116 * - set nsp (only chain action)<br>
117 * - {@link GoToTable} EXTERNAL MAPPER table<br>
119 * <i>Allow from tunnel flow</i><br>
120 * Priority = 65000<br>
122 * - Reg1 (set to 0xffffff) {@link NxmNxReg1}<br>
123 * - in_port (should be tunnel port) {@link NodeConnectorId}<br>
125 * - output:port (Reg7) {@link NxmNxReg7}<br>
127 * Traffic is sent from one {@link EndpointGroup} to the same EPG
129 * <i>Allow from same EPG flow</i><br>
130 * Priority = 65000<br>
132 * - Reg0 {@link NxmNxReg0}<br>
133 * - Reg2 {@link NxmNxReg2}<br>
135 * - output:port (Reg7) {@link NxmNxReg7}
137 * <i>Arp flow</i><br>
138 * Priority = 20000<br>
140 * - ethernet match (arp)<br>
141 * - Reg5 {@link NxmNxReg5}<br>
143 * - output:port (Reg7) {@link NxmNxReg7}
145 public class PolicyEnforcer extends FlowTable {
147 private static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
148 private static short TABLE_ID;
149 private static Instruction gotoEgressNatInstruction;
150 private static Instruction gotoExternalInstruction;
152 public PolicyEnforcer(OfContext ctx, short tableId) {
155 gotoEgressNatInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EGRESS_NAT());
156 gotoExternalInstruction = gotoTableIns(ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER());
160 public short getTableId() {
165 public void sync(Endpoint endpoint, OfWriter ofWriter) throws Exception {
166 Preconditions.checkNotNull(endpoint);
167 Preconditions.checkNotNull(ofWriter);
169 NodeId nodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint);
171 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
173 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
174 if (tunPort != null) {
175 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
177 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals =
178 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint);
179 if (srcEpFwdCxtOrdinals == null) {
180 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", endpoint);
183 for (EgKey sourceEpg : ctx.getEndpointManager().getEgKeysForEndpoint(endpoint)) {
184 for (EgKey destEpg : ctx.getCurrentPolicy().getPeers(sourceEpg)) {
185 Collection<Endpoint> destinationEndpoints = getEndpointsForGroup(destEpg);
186 for (Endpoint destinationEndpoint : destinationEndpoints) {
187 EndpointFwdCtxOrdinals dstEpFwdCxtOrdinals =
188 OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destinationEndpoint);
189 if (dstEpFwdCxtOrdinals == null) {
190 LOG.debug("Method getEndpointFwdCtxOrdinals returned null for EP {}", destinationEndpoint);
194 NetworkElements netElements =
195 new NetworkElements(endpoint, destinationEndpoint, sourceEpg, destEpg, nodeId, ctx);
197 // Get policy in both directions
198 Policy sourceEpgPolicy = ctx.getCurrentPolicy().getPolicy(destEpg, sourceEpg);
199 Policy destinationEpgPolicy = ctx.getCurrentPolicy().getPolicy(sourceEpg, destEpg);
201 // Resolve flows in both directions if possible according to policy. Get back
204 resolveSourceEpgPolicy(ofWriter, netElements, sourceEpgPolicy, destinationEpgPolicy);
206 ofWriter.writeFlow(nodeId, TABLE_ID, createArpFlow(srcEpFwdCxtOrdinals.getFdId()));
210 allowSameEpg(sourceEpg, endpoint, nodeId, ofWriter);
214 private Set<Endpoint> getEndpointsForGroup(EgKey epg) {
215 Set<Endpoint> destinationEndpoints = new HashSet<>();
216 destinationEndpoints.addAll(ctx.getEndpointManager().getEndpointsForGroup(epg));
217 destinationEndpoints.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(epg));
218 return destinationEndpoints;
221 private void resolveSourceEpgPolicy(OfWriter ofWriter, NetworkElements netElements, Policy directPolicy,
222 Policy reversedPolicy) {
224 List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> providedRules =
225 getActiveRulesBetweenEps(directPolicy, netElements.getDstEp(), netElements.getSrcEp());
226 List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> consumedRules =
227 getActiveRulesBetweenEps(reversedPolicy, netElements.getSrcEp(), netElements.getDstEp());
228 List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules;
229 if (!providedRules.isEmpty()) {
230 activeRules = providedRules;
232 activeRules = consumedRules;
234 int priority = 65000;
235 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRulesByConstraints : activeRules) {
236 Set<IpPrefix> sIpPrefixes;
237 Set<IpPrefix> dIpPrefixes;
238 if (providedRules.contains(activeRulesByConstraints)) {
239 sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey().getL3EpPrefixes());
240 dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey().getL3EpPrefixes());
242 sIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getColumnKey().getL3EpPrefixes());
243 dIpPrefixes = Policy.getIpPrefixesFrom(activeRulesByConstraints.getRowKey().getL3EpPrefixes());
245 for (RuleGroup rg : Ordering.from(new RuleGroupComparator())
246 .immutableSortedCopy(activeRulesByConstraints.getValue())) {
247 TenantId tenantId = rg.getContractTenant().getId();
248 IndexedTenant tenant = ctx.getTenant(tenantId);
249 for (Direction direction : new Direction[] {Direction.In, Direction.Out}) {
250 List<Rule> sameDirectionRules;
251 if (providedRules.contains(activeRulesByConstraints)) {
252 sameDirectionRules = uniteRulesByDirection(direction, rg.getRules(), getRules(consumedRules));
254 sameDirectionRules = uniteRulesByDirection(direction, null, rg.getRules());
256 for (Rule rule : Ordering.from(TenantUtils.RULE_COMPARATOR)
257 .immutableSortedCopy(sameDirectionRules)) {
258 createFlowsForRule(rule, getRules(providedRules), getRules(consumedRules), direction,
259 netElements, ofWriter, tenant, sIpPrefixes, dIpPrefixes, priority);
268 private List<Rule> uniteRulesByDirection (Direction direction, List<Rule> directRules, List<Rule> reversedRules) {
269 List<Rule> sameDirectionRules = findRulesInDirection(direction, directRules);
271 .addAll(findRulesInDirection(reverse(direction), reversedRules));
272 return sameDirectionRules;
275 private void createFlowsForRule(Rule rule, List<Rule> providedRules, List<Rule> consumedRules,
276 Direction direction, NetworkElements netElements,OfWriter ofWriter, IndexedTenant tenant, Set<IpPrefix> sIpPrefixes,
277 Set<IpPrefix> dIpPrefixes, int priority) {
278 List<Rule> reverseProvidedRules = findRulesInDirection(reverse(direction), providedRules);
279 List<String> resolvedSymmetricChains =
280 resolveSymetricChainActions(direction, rule, tenant, reverseProvidedRules, consumedRules);
281 if (resolvedSymmetricChains == null) {
282 LOG.debug("Rule {} skipped. Reason: asymmetric use of symmetric chain", rule);
285 // Create list of matches/actions. Also creates chain flows when
286 // specific action requires it
287 List<MatchBuilder> matches = null;
288 if (consumedRules.contains(rule)) {
289 matches = createMatches(direction, reverse(direction), netElements, tenant, rule,
290 sIpPrefixes, dIpPrefixes);
292 matches = createMatches(direction, direction, netElements, tenant, rule, sIpPrefixes,
295 List<ActionBuilder> actions = createActions(ofWriter, netElements, direction, tenant, rule,
296 resolvedSymmetricChains);
297 if (actions == null) {
302 createFlows(matches, actions, netElements, ofWriter, priority);
305 private List<String> resolveSymetricChainActions(Direction direction, Rule rule, IndexedTenant tenant,
306 List<Rule> reversedProvidedRules, List<Rule> consumedRules) {
307 List<String> chainNames = new ArrayList<>();
308 if (rule.getActionRef() != null) {
310 for (ActionRef actionRef : rule.getActionRef()) {
311 ActionInstance actionInstance = tenant.getAction(actionRef.getName());
312 if (actionInstance == null) {
315 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
316 if (action == null) {
319 if (action instanceof ChainAction) {
320 chainNames = getSymetricChainNames(actionInstance);
321 if (chainNames.isEmpty()) {
324 List<Rule> reversedRules = findRulesInDirection(reverse(direction), reversedProvidedRules);
325 reversedRules.addAll(findRulesInDirection(direction, consumedRules));
327 List<String> oppositeChainNames = new ArrayList<>();
328 for (Rule oppositeRule : reversedRules) {
329 if (oppositeRule.getActionRef() == null) {
332 for (ActionRef oppositeActionRef : oppositeRule.getActionRef()) {
333 ActionInstance oppositeActionInstance = tenant.getAction(oppositeActionRef.getName());
334 if (oppositeActionInstance == null) {
337 Action oppositeAction = SubjectFeatures.getAction(oppositeActionInstance.getActionDefinitionId());
338 if (oppositeAction == null) {
341 if (oppositeAction instanceof ChainAction) {
342 oppositeChainNames.addAll(getSymetricChainNames(oppositeActionInstance));
347 if (!oppositeChainNames.containsAll(chainNames)) {
350 if ((consumedRules.contains(rule) && (direction.equals(Direction.Out)))
351 || ((!consumedRules.contains(rule)) && direction.equals(Direction.In))) {
352 return new ArrayList<>();
360 private List<String> getSymetricChainNames(ActionInstance action) {
361 List<String> chainNames = new ArrayList<>();
362 for (ParameterValue param : action.getParameterValue()) {
363 if (param.getStringValue() != null
364 && param.getName().getValue().equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
365 String chainName = param.getStringValue();
366 ServiceFunctionPath sfcPath = ChainAction.getSfcPath(new SfcName(chainName));
367 if (sfcPath == null || sfcPath.getName() == null) {
370 if (sfcPath.isSymmetric()) {
371 chainNames.add(param.getStringValue());
378 private void allowSameEpg(EgKey epgKey, Endpoint sourceEp, NodeId nodeId, OfWriter ofWriter) throws Exception {
380 IndexedTenant tenant = ctx.getTenant(epgKey.getTenantId());
381 if (tenant != null) {
382 EndpointGroup group = tenant.getEndpointGroup(epgKey.getEgId());
384 LOG.debug("EPG {} does not exit and is used ", epgKey);
387 IntraGroupPolicy igp = group.getIntraGroupPolicy();
389 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
390 EndpointFwdCtxOrdinals srcEpFwdCxtOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, sourceEp);
391 if (srcEpFwdCxtOrdinals == null) {
392 LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", sourceEp);
394 int epgId = srcEpFwdCxtOrdinals.getEpgId();
395 ofWriter.writeFlow(nodeId, TABLE_ID, allowSameEpg(epgId));
400 // Return list of all rules with opposite direction
401 private List<Rule> findRulesInDirection(Direction direction, List<Rule> rules) {
402 List<Rule> sameDirectionRules = new ArrayList<>();
404 for (Rule ruleToCompare : rules) {
405 if (isSameDirection(direction, ruleToCompare)) {
406 sameDirectionRules.add(ruleToCompare);
410 return sameDirectionRules;
413 private boolean isSameDirection(Direction direction, Rule rule) {
414 for (ClassifierRef classifier : rule.getClassifierRef()) {
415 if (direction.equals(classifier.getDirection()) || direction.equals(Direction.Bidirectional)
416 || Direction.Bidirectional.equals(classifier.getDirection())) {
423 private List<Rule> getRules(List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> activeRules) {
424 List<Rule> rules = new ArrayList<>();
425 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> activeRule : activeRules) {
426 for (RuleGroup ruleGroup : activeRule.getValue()) {
427 for (Rule rule : ruleGroup.getRules()) {
435 private Flow createArpFlow(Integer fdId) {
437 Long etherType = FlowUtils.ARP;
438 // L2 Classifier so 20,000 for now
439 Integer priority = 20000;
441 MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
443 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
445 Match match = mb.build();
446 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "arp", match);
447 return base().setPriority(priority)
450 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
454 private Flow allowSameEpg(int epgId) {
456 MatchBuilder mb = new MatchBuilder();
457 addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, (long) epgId), RegMatch.of(NxmNxReg2.class, (long) epgId));
458 Match match = mb.build();
459 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "intraallow", match);
460 FlowBuilder flow = base().setId(flowId).setMatch(match).setPriority(65000).setInstructions(
461 instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
465 private Flow allowFromTunnel(NodeConnectorId tunPort) {
467 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
468 addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
469 Match match = mb.build();
470 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "tunnelallow", match);
471 FlowBuilder flow = base().setId(flowId).setMatch(match).setPriority(65000).setInstructions(
472 instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
477 private List<MatchBuilder> createMatches(Direction flowDirection, Direction classifierDirection,
478 NetworkElements netElements, IndexedTenant contractTenant, Rule rule, Set<IpPrefix> sIpPrefixes,
479 Set<IpPrefix> dIpPrefixes) {
480 Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
481 Set<ClassifierDefinitionId> classifiers = new HashSet<>();
482 for (ClassifierRef cr : rule.getClassifierRef()) {
484 if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
485 && !cr.getDirection().equals(classifierDirection)) {
489 // XXX - TODO - implement connection tracking (requires openflow
490 // extension and data plane support - in 2.4. Will need to handle
491 // case where we are working with mix of nodes.
493 ClassifierInstance ci = contractTenant.getClassifier(cr.getInstanceName());
495 // XXX TODO fail the match and raise an exception
496 LOG.warn("Classifier instance {} not found", cr.getInstanceName().getValue());
499 Classifier classifier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
500 if (classifier == null) {
501 // XXX TODO fail the match and raise an exception
502 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
505 classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
506 for (ParameterValue v : ci.getParameterValue()) {
507 if (paramsFromClassifier.get(v.getName().getValue()) == null) {
508 if (v.getIntValue() != null || v.getStringValue() != null || v.getRangeValue() != null) {
509 paramsFromClassifier.put(v.getName().getValue(), v);
512 if (!paramsFromClassifier.get(v.getName().getValue()).equals(v)) {
513 throw new IllegalArgumentException("Classification error in rule: " + rule.getName()
514 + ".\nCause: " + "Classification conflict detected at parameter " + v.getName());
519 if (classifiers.isEmpty()) {
522 List<Map<String, ParameterValue>> derivedParamsByName =
523 ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
524 List<MatchBuilder> flowMatchBuilders = new ArrayList<>();
525 for (Map<String, ParameterValue> params : derivedParamsByName) {
526 List<MatchBuilder> matchBuildersToResolve = new ArrayList<>();
527 if (sIpPrefixes.isEmpty() && dIpPrefixes.isEmpty()) {
528 matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, null, null));
529 } else if (!sIpPrefixes.isEmpty() && dIpPrefixes.isEmpty()) {
530 for (IpPrefix sIpPrefix : sIpPrefixes) {
531 matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, sIpPrefix, null));
533 } else if (sIpPrefixes.isEmpty() && !dIpPrefixes.isEmpty()) {
534 for (IpPrefix dIpPrefix : dIpPrefixes) {
535 matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, null, dIpPrefix));
538 for (IpPrefix sIpPrefix : sIpPrefixes) {
539 for (IpPrefix dIpPrefix : dIpPrefixes) {
540 matchBuildersToResolve.add(createBaseMatch(flowDirection, netElements, sIpPrefix, dIpPrefix));
544 for (ClassifierDefinitionId clDefId : classifiers) {
545 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
546 ClassificationResult result = classifier.updateMatch(matchBuildersToResolve, params);
547 if (!result.isSuccessfull()) {
548 // TODO consider different handling.
549 throw new IllegalArgumentException("Classification conflict detected in rule: " + rule.getName()
550 + ".\nCause: " + result.getErrorMessage());
552 matchBuildersToResolve = new ArrayList<>(result.getMatchBuilders());
554 flowMatchBuilders.addAll(matchBuildersToResolve);
556 return flowMatchBuilders;
559 private List<ActionBuilder> createActions(OfWriter ofWriter, NetworkElements netElements, Direction direction,
560 IndexedTenant contractTenant, Rule rule, List<String> resolvedSymmetricChains) {
561 List<ActionBuilder> actionBuilderList = new ArrayList<>();
562 if (rule.getActionRef() != null) {
564 // Pre-sort by references using order, then name
565 List<ActionRef> actionRefList = new ArrayList<>(rule.getActionRef());
566 Collections.sort(actionRefList, ActionRefComparator.INSTANCE);
568 for (ActionRef actionRef : actionRefList) {
569 ActionInstance actionInstance = contractTenant.getAction(actionRef.getName());
570 if (actionInstance == null) {
571 // XXX TODO fail the match and raise an exception
572 LOG.warn("Action instance {} not found", actionRef.getName().getValue());
575 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
576 if (action == null) {
577 // XXX TODO fail the match and raise an exception
578 LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
582 Map<String, Object> params = new HashMap<>();
583 if (actionInstance.getParameterValue() != null) {
584 for (ParameterValue v : actionInstance.getParameterValue()) {
585 if (v.getName() == null)
587 if (v.getIntValue() != null) {
588 params.put(v.getName().getValue(), v.getIntValue());
589 } else if (v.getStringValue() != null) {
590 params.put(v.getName().getValue(), v.getStringValue());
594 if (action instanceof ChainAction) {
595 ((ChainAction) action).setResolvedSymmetricChains(resolvedSymmetricChains);
598 // Convert the GBP Action to one or more OpenFlow Actions
599 if ((!(actionRefList.indexOf(actionRef) == (actionRefList.size() - 1)
600 && action.equals(SubjectFeatures.getAction(AllowActionDefinition.DEFINITION.getId()))))
601 && actionBuilderList != null) {
602 if (ctx.getDataBroker() != null) {
604 action.updateAction(actionBuilderList, params, actionRef.getOrder(), netElements, ofWriter, ctx, direction);
606 LOG.error("DataBroket is null. Cannot update action {}",
607 action.getActionDef().getName().getValue());
614 return actionBuilderList;
617 public static Direction reverse(Direction direction) {
618 if (direction.equals(Direction.In)) {
619 return Direction.Out;
620 } else if (direction.equals(Direction.Out)) {
623 return Direction.Bidirectional;
627 private void createFlows(List<MatchBuilder> flowMatchBuilders, List<ActionBuilder> actionBuilderList,
628 NetworkElements netElements, OfWriter ofWriter, int priority) {
629 FlowBuilder flow = base().setPriority(priority);
630 if (flowMatchBuilders == null) {
633 for (MatchBuilder mb : flowMatchBuilders) {
634 Match match = mb.build();
635 FlowId flowId = FlowIdUtils.newFlowId(TABLE_ID, "cg", match);
636 flow.setMatch(match).setId(flowId).setPriority(priority);
638 // If destination is External, the last Action ALLOW must be changed to goto
639 // NAT/External table.
640 // If actionBuilderList is empty (we removed the last Allow) then go straight to
641 // ExternalMapper table.
643 List<ExternalImplicitGroup> eigs = ctx.getTenant(netElements.getDstEp().getTenant())
646 .getExternalImplicitGroup();
647 boolean performNat = false;
648 for (EndpointL3 natEp : ctx.getEndpointManager().getL3EndpointsWithNat()) {
649 if (natEp.getMacAddress() != null && natEp.getL2Context() != null
650 && netElements.getSrcEp()
652 .equals(new EndpointKey(natEp.getL2Context(), natEp.getMacAddress()))
653 && EndpointManager.isExternal(netElements.getDstEp(), eigs)) {
658 if (actionBuilderList == null) {
659 // flow with this match should not appear on switch (e.g. chain action IN)
660 // //TODO - analyse, what happen for unknown action, SFC, etc.
663 if (actionBuilderList.isEmpty()) {
664 flow.setInstructions((performNat == true) ? instructions(gotoEgressNatInstruction) : instructions(
665 gotoExternalInstruction));
667 flow.setInstructions(instructions(applyActionIns(actionBuilderList),
668 (performNat == true) ? gotoEgressNatInstruction : gotoExternalInstruction));
670 ofWriter.writeFlow(netElements.getLocalNodeId(), TABLE_ID, flow.build());
674 private MatchBuilder createBaseMatch(Direction direction, NetworkElements netElements, IpPrefix sIpPrefix,
675 IpPrefix dIpPrefix) {
676 MatchBuilder baseMatch = new MatchBuilder();
677 if (direction.equals(Direction.In)) {
678 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) netElements.getDstEpOrdinals().getEpgId()),
679 RegMatch.of(NxmNxReg1.class, (long) netElements.getDstEpOrdinals().getCgId()),
680 RegMatch.of(NxmNxReg2.class, (long) netElements.getSrcEpOrdinals().getEpgId()),
681 RegMatch.of(NxmNxReg3.class, (long) netElements.getSrcEpOrdinals().getCgId()));
682 if (sIpPrefix != null) {
683 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, true));
685 if (dIpPrefix != null) {
686 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, false));
689 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, (long) netElements.getSrcEpOrdinals().getEpgId()),
690 RegMatch.of(NxmNxReg1.class, (long) netElements.getSrcEpOrdinals().getCgId()),
691 RegMatch.of(NxmNxReg2.class, (long) netElements.getDstEpOrdinals().getEpgId()),
692 RegMatch.of(NxmNxReg3.class, (long) netElements.getDstEpOrdinals().getCgId()));
693 if (sIpPrefix != null) {
694 baseMatch.setLayer3Match(createLayer3Match(sIpPrefix, false));
696 if (dIpPrefix != null) {
697 baseMatch.setLayer3Match(createLayer3Match(dIpPrefix, true));
703 private Layer3Match createLayer3Match(IpPrefix ipPrefix, boolean isSrc) {
704 if (ipPrefix.getIpv4Prefix() != null) {
706 return new Ipv4MatchBuilder().setIpv4Source(ipPrefix.getIpv4Prefix()).build();
708 return new Ipv4MatchBuilder().setIpv4Destination(ipPrefix.getIpv4Prefix()).build();
712 return new Ipv6MatchBuilder().setIpv6Source(ipPrefix.getIpv6Prefix()).build();
714 return new Ipv6MatchBuilder().setIpv6Destination(ipPrefix.getIpv6Prefix()).build();
719 // TODO: move to a common utils for all renderers
720 private List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> getActiveRulesBetweenEps(Policy policy,
721 Endpoint consEp, Endpoint provEp) {
722 List<Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>>> rulesWithEpConstraints = new ArrayList<>();
723 for (Cell<EndpointConstraint, EndpointConstraint, List<RuleGroup>> cell : policy.getRuleMap().cellSet()) {
724 EndpointConstraint consEpConstraint = cell.getRowKey();
725 EndpointConstraint provEpConstraint = cell.getColumnKey();
726 if (epMatchesConstraint(consEp, consEpConstraint) && epMatchesConstraint(provEp, provEpConstraint)) {
727 rulesWithEpConstraints.add(cell);
730 return rulesWithEpConstraints;
733 private boolean epMatchesConstraint(Endpoint ep, EndpointConstraint constraint) {
734 List<ConditionName> epConditions = Collections.emptyList();
735 if (ep.getCondition() != null) {
736 epConditions = ep.getCondition();
738 return constraint.getConditionSet().matches(epConditions);
742 * Private internal class for ordering Actions in Rules. The order is
743 * determined first by the value of the order parameter, with the lower
744 * order actions being applied first; for Actions with either the same order
745 * or no order, ordering is lexicographical by name.
747 private static class ActionRefComparator implements Comparator<ActionRef> {
749 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
752 public int compare(ActionRef arg0, ActionRef arg1) {
753 return ComparisonChain.start()
754 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
755 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
761 private static class RuleGroupComparator implements Comparator<RuleGroup> {
764 public int compare(RuleGroup arg0, RuleGroup arg1) {
765 return ComparisonChain.start()
766 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
767 .compare(arg0.getRelatedSubject().getValue(), arg1.getRelatedSubject().getValue()
768 ,Ordering.natural().nullsLast())