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.instructions;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
25 import javax.annotation.concurrent.Immutable;
27 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
28 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
29 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
30 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
31 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
32 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
33 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
34 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
35 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
37 import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
38 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
39 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
40 import org.opendaylight.groupbasedpolicy.resolver.Policy;
41 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
42 import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
74 import com.google.common.collect.ComparisonChain;
75 import com.google.common.collect.Ordering;
78 * Manage the table that enforces policy on the traffic. Traffic is denied
79 * unless specifically allowed by policy
81 public class PolicyEnforcer extends FlowTable {
83 protected static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
85 public static final short TABLE_ID = 3;
87 public PolicyEnforcer(OfContext ctx) {
92 public short getTableId() {
97 public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
99 flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
101 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
102 if (tunPort != null) {
103 flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
106 HashSet<CgPair> visitedPairs = new HashSet<>();
108 // Used for ARP flows
109 Set<Integer> fdIds = new HashSet<>();
111 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
112 for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
113 Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
114 for (EgKey dstEpgKey : peers) {
115 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey)) {
117 EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
119 EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
121 int dcgId = dstEpFwdCxtOrds.getCgId();
122 int depgId = dstEpFwdCxtOrds.getEpgId();
123 int scgId = srcEpFwdCxtOrds.getCgId();
124 int sepgId = srcEpFwdCxtOrds.getEpgId();
126 fdIds.add(srcEpFwdCxtOrds.getFdId());
128 List<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp);
129 ConditionGroup scg = policyInfo.getEgCondGroup(srcEpgKey, conds);
130 conds = ctx.getEndpointManager().getCondsForEndpoint(dstEp);
131 ConditionGroup dcg = policyInfo.getEgCondGroup(dstEpgKey, conds);
133 Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
134 List<RuleGroup> rgs = policy.getRules(dcg, scg);
135 CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
136 if (visitedPairs.contains(p))
139 syncPolicy(flowMap, nodeId, rgs, p);
142 policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
143 rgs = policy.getRules(scg, dcg);
144 p = new CgPair(sepgId, depgId, scgId, dcgId);
145 if (visitedPairs.contains(p))
148 syncPolicy(flowMap, nodeId, rgs, p);
155 // Set<Endpoint> visitedEps = new HashSet<>();
156 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
157 // visitedEps.add(srcEp);
158 for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
160 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
161 EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
162 IntraGroupPolicy igp = group.getIntraGroupPolicy();
164 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
165 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
167 // if(visitedEps.contains(dstEp)) {
170 // visitedEps.add(dstEp);
171 EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
173 EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
175 int depgId = dstEpFwdCxtOrds.getEpgId();
176 int sepgId = srcEpFwdCxtOrds.getEpgId();
177 flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
178 flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
184 // Write ARP flows per flood domain.
185 for (Integer fdId : fdIds) {
186 flowMap.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
190 private Flow createArpFlow(Integer fdId) {
192 Long etherType = FlowUtils.ARP;
193 // L2 Classifier so 20,000 for now
194 Integer priority = 20000;
195 FlowId flowid = new FlowId(new StringBuilder().append("arp")
202 MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
204 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
206 Flow flow = base().setPriority(priority)
208 .setMatch(mb.build())
209 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
214 private Flow allowSameEpg(int sepgId, int depgId) {
216 FlowId flowId = new FlowId(new StringBuilder().append("intraallow|").append(sepgId).toString());
217 MatchBuilder mb = new MatchBuilder();
218 addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
219 RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
220 FlowBuilder flow = base().setId(flowId)
221 .setMatch(mb.build())
223 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
227 private Flow allowFromTunnel(NodeConnectorId tunPort) {
229 FlowId flowId = new FlowId("tunnelallow");
230 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
231 addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
232 FlowBuilder flow = base().setId(flowId)
233 .setMatch(mb.build())
235 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
240 private void syncPolicy(FlowMap flowMap, NodeId nodeId, List<RuleGroup> rgs, CgPair p) {
241 int priority = 65000;
242 for (RuleGroup rg : rgs) {
243 TenantId tenantId = rg.getContractTenant().getId();
244 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
245 for (Rule r : rg.getRules()) {
246 syncDirection(flowMap, nodeId, tenant, p, r, Direction.In, priority);
247 syncDirection(flowMap, nodeId, tenant, p, r, Direction.Out, priority);
255 * Private internal class for ordering Actions in Rules. The order is
256 * determined first by the value of the order parameter, with the lower
257 * order actions being applied first; for Actions with either the same order
258 * or no order, ordering is lexicographical by name.
260 private static class ActionRefComparator implements Comparator<ActionRef> {
262 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
265 public int compare(ActionRef arg0, ActionRef arg1) {
266 return ComparisonChain.start()
267 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
268 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
274 private void syncDirection(FlowMap flowMap, NodeId nodeId, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
275 Direction direction, int priority) {
277 * Create the ordered action list. The implicit action is "allow", and
278 * is therefore always in the list
280 * TODO: revisit implicit vs. default for "allow" TODO: look into
281 * incorporating operational policy for actions
284 // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
285 // referencing in sort
286 List<ActionBuilder> abl = new ArrayList<ActionBuilder>();
287 if (rule.getActionRef() != null) {
289 * Pre-sort by references using order, then name
291 List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
292 Collections.sort(arl, ActionRefComparator.INSTANCE);
294 for (ActionRef ar : arl) {
295 ActionInstance ai = contractTenant.getAction(ar.getName());
297 // XXX TODO fail the match and raise an exception
298 LOG.warn("Action instance {} not found", ar.getName().getValue());
301 Action act = SubjectFeatures.getAction(ai.getActionDefinitionId());
303 // XXX TODO fail the match and raise an exception
304 LOG.warn("Action definition {} not found", ai.getActionDefinitionId().getValue());
308 Map<String, Object> params = new HashMap<>();
309 if (ai.getParameterValue() != null) {
310 for (ParameterValue v : ai.getParameterValue()) {
311 if (v.getName() == null)
313 if (v.getIntValue() != null) {
314 params.put(v.getName().getValue(), v.getIntValue());
315 } else if (v.getStringValue() != null) {
316 params.put(v.getName().getValue(), v.getStringValue());
321 * Convert the GBP Action to one or more OpenFlow Actions
323 abl = act.updateAction(abl, params, ar.getOrder());
326 Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
327 abl = act.updateAction(abl, new HashMap<String, Object>(), 0);
330 Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
331 Set<ClassifierDefinitionId> classifiers = new HashSet<>();
332 for (ClassifierRef cr : rule.getClassifierRef()) {
333 if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
334 && !cr.getDirection().equals(direction)) {
338 // XXX - TODO - implement connection tracking (requires openflow
339 // extension and data plane support - in 2.4. Will need to handle
340 // case where we are working with mix of nodes.
342 ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
344 // XXX TODO fail the match and raise an exception
345 LOG.warn("Classifier instance {} not found", cr.getName().getValue());
348 Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
350 // XXX TODO fail the match and raise an exception
351 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
354 classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
355 for (ParameterValue v : ci.getParameterValue()) {
357 if (v.getIntValue() != null) {
358 paramsFromClassifier.put(v.getName().getValue(), v);
359 } else if (v.getStringValue() != null) {
360 paramsFromClassifier.put(v.getName().getValue(), v);
361 } else if (v.getRangeValue() != null) {
362 paramsFromClassifier.put(v.getName().getValue(), v);
366 List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
368 for (Map<String, ParameterValue> params : derivedParamsByName) {
369 for (ClassifierDefinitionId clDefId : classifiers) {
370 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
371 StringBuilder idb = new StringBuilder();
372 // XXX - TODO - implement connection tracking (requires openflow
373 // extension and data plane support - in 2.4. Will need to handle
374 // case where we are working with mix of nodes.
376 MatchBuilder baseMatch = new MatchBuilder();
377 if (direction.equals(Direction.In)) {
378 idb.append(cgPair.sepg)
380 .append(cgPair.scgId)
384 .append(cgPair.dcgId)
387 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
388 RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
389 RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
390 RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
392 idb.append(cgPair.depg)
394 .append(cgPair.dcgId)
398 .append(cgPair.scgId)
401 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
402 RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
403 RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
404 RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
407 List<MatchBuilder> matches = new ArrayList<>();
408 matches.add(baseMatch);
410 ClassificationResult result = classifier.updateMatch(matches, params);
411 if (!result.isSuccessfull()) {
412 // TODO consider different handling.
413 throw new IllegalArgumentException(result.getErrorMessage());
415 String baseId = idb.toString();
416 FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
417 for (MatchBuilder match : result.getMatchBuilders()) {
418 Match m = match.build();
419 FlowId flowId = new FlowId(baseId + "|" + m.toString());
422 .setPriority(Integer.valueOf(priority))
423 .setInstructions(instructions(applyActionIns(abl)));
424 flowMap.writeFlow(nodeId, TABLE_ID, flow.build());
431 private static class CgPair {
433 private final int sepg;
434 private final int depg;
435 private final int scgId;
436 private final int dcgId;
438 public CgPair(int sepg, int depg, int scgId, int dcgId) {
447 public int hashCode() {
448 final int prime = 31;
450 result = prime * result + dcgId;
451 result = prime * result + depg;
452 result = prime * result + scgId;
453 result = prime * result + sepg;
458 public boolean equals(Object obj) {
463 if (getClass() != obj.getClass())
465 CgPair other = (CgPair) obj;
466 if (dcgId != other.dcgId)
468 if (depg != other.depg)
470 if (scgId != other.scgId)
472 if (sepg != other.sepg)