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.controller.md.sal.binding.api.ReadWriteTransaction;
28 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
29 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
30 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
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;
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.ConditionName;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 import com.google.common.collect.ComparisonChain;
73 import com.google.common.collect.Ordering;
76 * Manage the table that enforces policy on the traffic. Traffic is denied
77 * unless specifically allowed by policy
80 public class PolicyEnforcer extends FlowTable {
81 protected static final Logger LOG =
82 LoggerFactory.getLogger(PolicyEnforcer.class);
84 public static final short TABLE_ID = 3;
86 public PolicyEnforcer(OfContext ctx) {
91 public short getTableId() {
96 public void sync(ReadWriteTransaction t, InstanceIdentifier<Table> tiid,
97 Map<String, FlowCtx> flowMap, NodeId nodeId,
98 PolicyInfo policyInfo, Dirty dirty)
100 dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
101 allowFromTunnel(t, tiid, flowMap, nodeId);
103 HashSet<CgPair> visitedPairs = new HashSet<>();
105 for (EgKey sepg : ctx.getEndpointManager().getGroupsForNode(nodeId)) {
106 // Allow traffic within the same endpoint group if the policy
108 IndexedTenant tenant =
109 ctx.getPolicyResolver().getTenant(sepg.getTenantId());
110 EndpointGroup group =
111 tenant.getEndpointGroup(sepg.getEgId());
112 IntraGroupPolicy igp = group.getIntraGroupPolicy();
114 ctx.getPolicyManager().getContextOrdinal(sepg.getTenantId(),
116 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
117 allowSameEpg(t, tiid, flowMap, nodeId, sepgId);
120 for (Endpoint src : ctx.getEndpointManager().getEPsForNode(nodeId, sepg)) {
121 if (src.getTenant() == null || src.getEndpointGroup() == null)
124 List<ConditionName> conds =
125 ctx.getEndpointManager().getCondsForEndpoint(src);
126 ConditionGroup scg = policyInfo.getEgCondGroup(sepg, conds);
127 int scgId = ctx.getPolicyManager().getCondGroupOrdinal(scg);
129 Set<EgKey> peers = policyInfo.getPeers(sepg);
130 for (EgKey depg : peers) {
132 ctx.getPolicyManager().getContextOrdinal(depg.getTenantId(),
135 for (Endpoint dst : ctx.getEndpointManager().getEndpointsForGroup(depg)) {
137 conds = ctx.getEndpointManager().getCondsForEndpoint(dst);
139 policyInfo.getEgCondGroup(new EgKey(dst.getTenant(),
140 dst.getEndpointGroup()),
142 int dcgId = ctx.getPolicyManager().getCondGroupOrdinal(dcg);
144 CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
145 if (visitedPairs.contains(p)) continue;
147 syncPolicy(t, tiid, flowMap, nodeId, policyInfo,
148 p, depg, sepg, dcg, scg);
150 p = new CgPair(sepgId, depgId, scgId, dcgId);
151 if (visitedPairs.contains(p)) continue;
153 syncPolicy(t, tiid, flowMap, nodeId, policyInfo,
154 p, sepg, depg, scg, dcg);
161 private void allowSameEpg(ReadWriteTransaction t,
162 InstanceIdentifier<Table> tiid,
163 Map<String, FlowCtx> flowMap, NodeId nodeId,
165 FlowId flowId = new FlowId(new StringBuilder()
166 .append("intraallow|")
167 .append(sepgId).toString());
168 if (visit(flowMap, flowId.getValue())) {
169 MatchBuilder mb = new MatchBuilder();
171 RegMatch.of(NxmNxReg0.class,Long.valueOf(sepgId)),
172 RegMatch.of(NxmNxReg2.class,Long.valueOf(sepgId)));
173 FlowBuilder flow = base()
175 .setMatch(mb.build())
177 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
178 writeFlow(t, tiid, flow.build());
182 private void allowFromTunnel(ReadWriteTransaction t,
183 InstanceIdentifier<Table> tiid,
184 Map<String, FlowCtx> flowMap, NodeId nodeId) {
185 NodeConnectorId tunPort =
186 ctx.getSwitchManager().getTunnelPort(nodeId);
187 if (tunPort == null) return;
189 FlowId flowId = new FlowId("tunnelallow");
190 if (visit(flowMap, flowId.getValue())) {
191 MatchBuilder mb = new MatchBuilder()
194 RegMatch.of(NxmNxReg1.class,Long.valueOf(0xffffff)));
195 FlowBuilder flow = base()
197 .setMatch(mb.build())
199 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
200 writeFlow(t, tiid, flow.build());
204 private void syncPolicy(ReadWriteTransaction t,
205 InstanceIdentifier<Table> tiid,
206 Map<String, FlowCtx> flowMap, NodeId nodeId,
207 PolicyInfo policyInfo,
208 CgPair p, EgKey sepg, EgKey depg,
209 ConditionGroup scg, ConditionGroup dcg)
211 // XXX - TODO raise an exception for rules between the same
212 // endpoint group that are asymmetric
213 Policy policy = policyInfo.getPolicy(sepg, depg);
214 List<RuleGroup> rgs = policy.getRules(scg, dcg);
216 int priority = 65000;
217 for (RuleGroup rg : rgs) {
218 TenantId tenantId = rg.getContractTenant().getId();
219 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
220 for (Rule r : rg.getRules()) {
221 syncDirection(t, tiid, flowMap, nodeId, tenant,
222 p, r, Direction.In, priority);
223 syncDirection(t, tiid, flowMap, nodeId, tenant,
224 p, r, Direction.Out, priority);
232 * Private internal class for ordering Actions in Rules. The
233 * order is determined first by the value of the order parameter,
234 * with the lower order actions being applied first; for Actions
235 * with either the same order or no order, ordering is lexicographical
241 private static class ActionRefComparator implements Comparator<ActionRef> {
242 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
245 public int compare(ActionRef arg0, ActionRef arg1) {
246 return ComparisonChain.start()
247 .compare(arg0.getOrder(), arg1.getOrder(),
248 Ordering.natural().nullsLast())
249 .compare(arg0.getName().getValue(), arg1.getName().getValue(),
250 Ordering.natural().nullsLast())
256 private void syncDirection(ReadWriteTransaction t,
257 InstanceIdentifier<Table> tiid,
258 Map<String, FlowCtx> flowMap, NodeId nodeId,
259 IndexedTenant contractTenant,
260 CgPair p, Rule r, Direction d, int priority) {
262 * Create the ordered action list. The implicit action is
263 * "allow", and is therefore always in the list
265 * TODO: revisit implicit vs. default for "allow"
266 * TODO: look into incorporating operational policy for actions
268 List<ActionBuilder> abl = new ArrayList<ActionBuilder>();
269 if (r.getActionRef() != null) {
271 * Pre-sort by references using order, then name
273 List<ActionRef> arl = new ArrayList<ActionRef>(r.getActionRef());
274 Collections.sort(arl, ActionRefComparator.INSTANCE);
276 for (ActionRef ar: arl) {
277 ActionInstance ai = contractTenant.getAction(ar.getName());
279 // XXX TODO fail the match and raise an exception
280 LOG.warn("Action instance {} not found",
281 ar.getName().getValue());
284 Action act = SubjectFeatures.getAction(ai.getActionDefinitionId());
286 // XXX TODO fail the match and raise an exception
287 LOG.warn("Action definition {} not found",
288 ai.getActionDefinitionId().getValue());
292 Map<String,Object> params = new HashMap<>();
293 if (ai.getParameterValue() != null) {
294 for (ParameterValue v : ai.getParameterValue()) {
295 if (v.getName() == null) continue;
296 if (v.getIntValue() != null) {
297 params.put(v.getName().getValue(), v.getIntValue());
298 } else if (v.getStringValue() != null) {
299 params.put(v.getName().getValue(), v.getStringValue());
304 * Convert the GBP Action to one or more OpenFlow
307 abl = act.updateAction(abl, params, ar.getOrder());
311 Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
312 abl = act.updateAction(abl, new HashMap<String,Object>(), 0);
315 for (ClassifierRef cr : r.getClassifierRef()) {
316 if (cr.getDirection() != null &&
317 !cr.getDirection().equals(Direction.Bidirectional) &&
318 !cr.getDirection().equals(d))
321 StringBuilder idb = new StringBuilder();
322 // XXX - TODO - implement connection tracking (requires openflow
323 // extension and data plane support - in 2.4. Will need to handle
324 // case where we are working with mix of nodes.
326 MatchBuilder baseMatch = new MatchBuilder();
328 if (d.equals(Direction.In)) {
338 addNxRegMatch(baseMatch,
339 RegMatch.of(NxmNxReg0.class,Long.valueOf(p.sepg)),
340 RegMatch.of(NxmNxReg1.class,Long.valueOf(p.scgId)),
341 RegMatch.of(NxmNxReg2.class,Long.valueOf(p.depg)),
342 RegMatch.of(NxmNxReg3.class,Long.valueOf(p.dcgId)));
353 addNxRegMatch(baseMatch,
354 RegMatch.of(NxmNxReg0.class,Long.valueOf(p.depg)),
355 RegMatch.of(NxmNxReg1.class,Long.valueOf(p.dcgId)),
356 RegMatch.of(NxmNxReg2.class,Long.valueOf(p.sepg)),
357 RegMatch.of(NxmNxReg3.class,Long.valueOf(p.scgId)));
360 ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
362 // XXX TODO fail the match and raise an exception
363 LOG.warn("Classifier instance {} not found",
364 cr.getName().getValue());
367 Classifier cfier = SubjectFeatures
368 .getClassifier(ci.getClassifierDefinitionId());
370 // XXX TODO fail the match and raise an exception
371 LOG.warn("Classifier definition {} not found",
372 ci.getClassifierDefinitionId().getValue());
376 Map<String,ParameterValue> params = new HashMap<>();
377 for (ParameterValue v : ci.getParameterValue()) {
378 if (v.getIntValue() != null) {
379 params.put(v.getName().getValue(), v);
380 } else if (v.getStringValue() != null) {
381 params.put(v.getName().getValue(), v);
382 } else if (v.getRangeValue() != null) {
383 params.put(v.getName().getValue(), v);
386 List<Map<String, ParameterValue>> derivedParams = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(params);
387 for (Map<String, ParameterValue> flowParams : derivedParams) {
388 List<MatchBuilder> matches = Collections.singletonList(new MatchBuilder(baseMatch.build()));
389 ClassificationResult result = cfier.updateMatch(matches, flowParams);
390 if(!result.isSuccessfull()) {
391 //TODO consider different handling.
392 throw new IllegalArgumentException(result.getErrorMessage());
394 String baseId = idb.toString();
395 FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
396 for (MatchBuilder match : result.getMatchBuilders()) {
397 Match m = match.build();
398 FlowId flowId = new FlowId(baseId + "|" + m.toString());
399 if (visit(flowMap, flowId.getValue())) {
400 flow.setMatch(m).setId(flowId).setPriority(Integer.valueOf(priority))
401 .setInstructions(instructions(applyActionIns(abl)));
402 writeFlow(t, tiid, flow.build());
410 private static class CgPair {
411 private final int sepg;
412 private final int depg;
413 private final int scgId;
414 private final int dcgId;
416 public CgPair(int sepg, int depg, int scgId, int dcgId) {
425 public int hashCode() {
426 final int prime = 31;
428 result = prime * result + dcgId;
429 result = prime * result + depg;
430 result = prime * result + scgId;
431 result = prime * result + sepg;
436 public boolean equals(Object obj) {
441 if (getClass() != obj.getClass())
443 CgPair other = (CgPair) obj;
444 if (dcgId != other.dcgId)
446 if (depg != other.depg)
448 if (scgId != other.scgId)
450 if (sepg != other.sepg)