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.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.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
71 import com.google.common.collect.ComparisonChain;
72 import com.google.common.collect.Ordering;
75 * Manage the table that enforces policy on the traffic. Traffic is denied
76 * unless specifically allowed by policy
78 public class PolicyEnforcer extends FlowTable {
79 protected static final Logger LOG =
80 LoggerFactory.getLogger(PolicyEnforcer.class);
82 public static final short TABLE_ID = 3;
84 public PolicyEnforcer(OfContext ctx) {
89 public short getTableId() {
94 public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
96 flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
98 NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId);
99 if (tunPort != null) {
100 flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
103 HashSet<CgPair> visitedPairs = new HashSet<>();
105 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
106 for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
107 Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
108 for (EgKey dstEpgKey : peers) {
109 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey)) {
111 EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
112 EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dstEp);
113 int dcgId = dstEpFwdCxtOrds.getCgId();
114 int depgId = dstEpFwdCxtOrds.getEpgId();
115 int scgId = srcEpFwdCxtOrds.getCgId();
116 int sepgId = srcEpFwdCxtOrds.getEpgId();
118 List<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp);
119 ConditionGroup scg = policyInfo.getEgCondGroup(srcEpgKey, conds);
120 conds = ctx.getEndpointManager().getCondsForEndpoint(dstEp);
121 ConditionGroup dcg = policyInfo.getEgCondGroup(dstEpgKey, conds);
123 CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
124 if (visitedPairs.contains(p))
127 syncPolicy(flowMap, nodeId, policyInfo,
128 p, dstEpgKey, srcEpgKey, dcg, scg);
131 p = new CgPair(sepgId, depgId, scgId, dcgId);
132 if (visitedPairs.contains(p))
135 syncPolicy(flowMap, nodeId, policyInfo,
136 p, srcEpgKey, dstEpgKey, scg, dcg);
143 // Set<Endpoint> visitedEps = new HashSet<>();
144 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
145 // visitedEps.add(srcEp);
146 for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
148 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
149 EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
150 IntraGroupPolicy igp = group.getIntraGroupPolicy();
152 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
153 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
155 // if(visitedEps.contains(dstEp)) {
158 // visitedEps.add(dstEp);
159 EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
160 EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dstEp);
161 int depgId = dstEpFwdCxtOrds.getEpgId();
162 int sepgId = srcEpFwdCxtOrds.getEpgId();
163 flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
164 flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
172 private Flow allowSameEpg(int sepgId, int depgId) {
173 FlowId flowId = new FlowId(new StringBuilder()
174 .append("intraallow|")
175 .append(sepgId).toString());
176 MatchBuilder mb = new MatchBuilder();
178 RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
179 RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
180 FlowBuilder flow = base()
182 .setMatch(mb.build())
184 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
188 private Flow allowFromTunnel(NodeConnectorId tunPort) {
191 FlowId flowId = new FlowId("tunnelallow");
192 MatchBuilder mb = new MatchBuilder()
195 RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
196 FlowBuilder flow = base()
198 .setMatch(mb.build())
200 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
205 private void syncPolicy(FlowMap flowMap, NodeId nodeId,
206 PolicyInfo policyInfo,
207 CgPair p, EgKey sepg, EgKey depg,
208 ConditionGroup scg, ConditionGroup dcg)
210 // XXX - TODO raise an exception for rules between the same
211 // endpoint group that are asymmetric
212 Policy policy = policyInfo.getPolicy(sepg, depg);
213 List<RuleGroup> rgs = policy.getRules(scg, dcg);
215 int priority = 65000;
216 for (RuleGroup rg : rgs) {
217 TenantId tenantId = rg.getContractTenant().getId();
218 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
219 for (Rule r : rg.getRules()) {
220 syncDirection(flowMap, nodeId, tenant,
221 p, r, Direction.In, priority);
222 syncDirection(flowMap, nodeId, tenant,
223 p, r, Direction.Out, priority);
231 * Private internal class for ordering Actions in Rules. The order is
232 * determined first by the value of the order parameter, with the lower
233 * order actions being applied first; for Actions with either the same order
234 * or no order, ordering is lexicographical by name.
237 private static class ActionRefComparator implements Comparator<ActionRef> {
238 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
241 public int compare(ActionRef arg0, ActionRef arg1) {
242 return ComparisonChain.start()
243 .compare(arg0.getOrder(), arg1.getOrder(),
244 Ordering.natural().nullsLast())
245 .compare(arg0.getName().getValue(), arg1.getName().getValue(),
246 Ordering.natural().nullsLast())
252 private void syncDirection(FlowMap flowMap, NodeId nodeId, IndexedTenant contractTenant,
253 CgPair cgPair, Rule rule, Direction direction, int priority) {
255 * Create the ordered action list. The implicit action is "allow", and
256 * is therefore always in the list
258 * TODO: revisit implicit vs. default for "allow" TODO: look into
259 * incorporating operational policy for actions
262 //TODO: can pass Comparator ActionRefComparator to List constructor, rather than referencing in sort
263 List<ActionBuilder> abl = new ArrayList<ActionBuilder>();
264 if (rule.getActionRef() != null) {
266 * Pre-sort by references using order, then name
268 List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
269 Collections.sort(arl, ActionRefComparator.INSTANCE);
271 for (ActionRef ar : arl) {
272 ActionInstance ai = contractTenant.getAction(ar.getName());
274 // XXX TODO fail the match and raise an exception
275 LOG.warn("Action instance {} not found",
276 ar.getName().getValue());
279 Action act = SubjectFeatures.getAction(ai.getActionDefinitionId());
281 // XXX TODO fail the match and raise an exception
282 LOG.warn("Action definition {} not found",
283 ai.getActionDefinitionId().getValue());
287 Map<String, Object> params = new HashMap<>();
288 if (ai.getParameterValue() != null) {
289 for (ParameterValue v : ai.getParameterValue()) {
290 if (v.getName() == null)
292 if (v.getIntValue() != null) {
293 params.put(v.getName().getValue(), v.getIntValue());
294 } else if (v.getStringValue() != null) {
295 params.put(v.getName().getValue(), v.getStringValue());
300 * Convert the GBP Action to one or more OpenFlow Actions
302 abl = act.updateAction(abl, params, ar.getOrder());
306 Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
307 abl = act.updateAction(abl, new HashMap<String, Object>(), 0);
310 for (ClassifierRef cr : rule.getClassifierRef()) {
311 if (cr.getDirection() != null &&
312 !cr.getDirection().equals(Direction.Bidirectional) &&
313 !cr.getDirection().equals(direction)) {
317 StringBuilder idb = new StringBuilder();
318 // XXX - TODO - implement connection tracking (requires openflow
319 // extension and data plane support - in 2.4. Will need to handle
320 // case where we are working with mix of nodes.
322 MatchBuilder baseMatch = new MatchBuilder();
324 if (direction.equals(Direction.In)) {
325 idb.append(cgPair.sepg)
327 .append(cgPair.scgId)
331 .append(cgPair.dcgId)
334 addNxRegMatch(baseMatch,
335 RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
336 RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
337 RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
338 RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
340 idb.append(cgPair.depg)
342 .append(cgPair.dcgId)
346 .append(cgPair.scgId)
349 addNxRegMatch(baseMatch,
350 RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
351 RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
352 RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
353 RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
356 ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
358 // XXX TODO fail the match and raise an exception
359 LOG.warn("Classifier instance {} not found",
360 cr.getName().getValue());
363 Classifier cfier = SubjectFeatures
364 .getClassifier(ci.getClassifierDefinitionId());
366 // XXX TODO fail the match and raise an exception
367 LOG.warn("Classifier definition {} not found",
368 ci.getClassifierDefinitionId().getValue());
372 Map<String,ParameterValue> params = new HashMap<>();
373 for (ParameterValue v : ci.getParameterValue()) {
375 if (v.getIntValue() != null) {
376 params.put(v.getName().getValue(), v);
377 } else if (v.getStringValue() != null) {
378 params.put(v.getName().getValue(), v);
379 } else if (v.getRangeValue() != null) {
380 params.put(v.getName().getValue(), v);
383 List<Map<String, ParameterValue>> derivedParams = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(params);
384 for (Map<String, ParameterValue> flowParams : derivedParams) {
385 List<MatchBuilder> matches = Collections.singletonList(new MatchBuilder(baseMatch.build()));
386 ClassificationResult result = cfier.updateMatch(matches, flowParams);
387 if(!result.isSuccessfull()) {
388 //TODO consider different handling.
389 throw new IllegalArgumentException(result.getErrorMessage());
391 String baseId = idb.toString();
392 FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
393 for (MatchBuilder match : result.getMatchBuilders()) {
394 Match m = match.build();
395 FlowId flowId = new FlowId(baseId + "|" + m.toString());
398 .setPriority(Integer.valueOf(priority))
399 .setInstructions(instructions(applyActionIns(abl)));
400 flowMap.writeFlow(nodeId, TABLE_ID, flow.build());
409 private static class CgPair {
410 private final int sepg;
411 private final int depg;
412 private final int scgId;
413 private final int dcgId;
415 public CgPair(int sepg, int depg, int scgId, int dcgId) {
424 public int hashCode() {
425 final int prime = 31;
427 result = prime * result + dcgId;
428 result = prime * result + depg;
429 result = prime * result + scgId;
430 result = prime * result + sepg;
435 public boolean equals(Object obj) {
440 if (getClass() != obj.getClass())
442 CgPair other = (CgPair) obj;
443 if (dcgId != other.dcgId)
445 if (depg != other.depg)
447 if (scgId != other.scgId)
449 if (sepg != other.sepg)