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.node.SwitchManager;
32 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
33 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
34 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
35 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ParamDerivator;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
38 import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
39 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
40 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
41 import org.opendaylight.groupbasedpolicy.resolver.Policy;
42 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
43 import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
75 import com.google.common.collect.ComparisonChain;
76 import com.google.common.collect.Ordering;
79 * Manage the table that enforces policy on the traffic. Traffic is denied
80 * unless specifically allowed by policy
82 public class PolicyEnforcer extends FlowTable {
84 protected static final Logger LOG = LoggerFactory.getLogger(PolicyEnforcer.class);
86 public static final short TABLE_ID = 3;
88 public PolicyEnforcer(OfContext ctx) {
93 public short getTableId() {
98 public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
100 flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
102 NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class);
103 if (tunPort != null) {
104 flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
107 HashSet<CgPair> visitedPairs = new HashSet<>();
109 // Used for ARP flows
110 Set<Integer> fdIds = new HashSet<>();
112 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
113 for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
114 Set<EgKey> peers = policyInfo.getPeers(srcEpgKey);
115 for (EgKey dstEpgKey : peers) {
116 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(dstEpgKey)) {
118 EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
120 EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
122 int dcgId = dstEpFwdCxtOrds.getCgId();
123 int depgId = dstEpFwdCxtOrds.getEpgId();
124 int scgId = srcEpFwdCxtOrds.getCgId();
125 int sepgId = srcEpFwdCxtOrds.getEpgId();
126 NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
127 fdIds.add(srcEpFwdCxtOrds.getFdId());
129 List<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp);
130 ConditionGroup scg = policyInfo.getEgCondGroup(srcEpgKey, conds);
131 conds = ctx.getEndpointManager().getCondsForEndpoint(dstEp);
132 ConditionGroup dcg = policyInfo.getEgCondGroup(dstEpgKey, conds);
134 Policy policy = policyInfo.getPolicy(dstEpgKey, srcEpgKey);
135 List<RuleGroup> rgs = policy.getRules(dcg, scg);
136 CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
137 if (visitedPairs.contains(p))
140 syncPolicy(flowMap, netElements, rgs, p);
143 policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
144 rgs = policy.getRules(scg, dcg);
145 p = new CgPair(sepgId, depgId, scgId, dcgId);
146 if (visitedPairs.contains(p))
149 syncPolicy(flowMap, netElements, rgs, p);
156 // Set<Endpoint> visitedEps = new HashSet<>();
157 for (Endpoint srcEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
158 // visitedEps.add(srcEp);
159 for (EgKey srcEpgKey : ctx.getEndpointManager().getEgKeysForEndpoint(srcEp)) {
161 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(srcEpgKey.getTenantId());
162 EndpointGroup group = tenant.getEndpointGroup(srcEpgKey.getEgId());
163 IntraGroupPolicy igp = group.getIntraGroupPolicy();
165 if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
166 for (Endpoint dstEp : ctx.getEndpointManager().getEndpointsForGroup(srcEpgKey)) {
168 // if(visitedEps.contains(dstEp)) {
171 // visitedEps.add(dstEp);
172 EndpointFwdCtxOrdinals srcEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
174 EndpointFwdCtxOrdinals dstEpFwdCxtOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
176 int depgId = dstEpFwdCxtOrds.getEpgId();
177 int sepgId = srcEpFwdCxtOrds.getEpgId();
178 flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(sepgId, depgId));
179 flowMap.writeFlow(nodeId, TABLE_ID, allowSameEpg(depgId, sepgId));
185 // Write ARP flows per flood domain.
186 for (Integer fdId : fdIds) {
187 flowMap.writeFlow(nodeId, TABLE_ID, createArpFlow(fdId));
191 private Flow createArpFlow(Integer fdId) {
193 Long etherType = FlowUtils.ARP;
194 // L2 Classifier so 20,000 for now
195 Integer priority = 20000;
196 FlowId flowid = new FlowId(new StringBuilder().append("arp")
203 MatchBuilder mb = new MatchBuilder().setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
205 addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
207 Flow flow = base().setPriority(priority)
209 .setMatch(mb.build())
210 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))))
215 private Flow allowSameEpg(int sepgId, int depgId) {
217 FlowId flowId = new FlowId(new StringBuilder().append("intraallow|").append(sepgId).toString());
218 MatchBuilder mb = new MatchBuilder();
219 addNxRegMatch(mb, RegMatch.of(NxmNxReg0.class, Long.valueOf(sepgId)),
220 RegMatch.of(NxmNxReg2.class, Long.valueOf(depgId)));
221 FlowBuilder flow = base().setId(flowId)
222 .setMatch(mb.build())
224 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
228 private Flow allowFromTunnel(NodeConnectorId tunPort) {
230 FlowId flowId = new FlowId("tunnelallow");
231 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
232 addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, Long.valueOf(0xffffff)));
233 FlowBuilder flow = base().setId(flowId)
234 .setMatch(mb.build())
236 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
241 private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> rgs, CgPair p) {
242 int priority = 65000;
243 for (RuleGroup rg : rgs) {
244 TenantId tenantId = rg.getContractTenant().getId();
245 IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
246 for (Rule r : rg.getRules()) {
247 syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority);
248 syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority);
256 * Private internal class for ordering Actions in Rules. The order is
257 * determined first by the value of the order parameter, with the lower
258 * order actions being applied first; for Actions with either the same order
259 * or no order, ordering is lexicographical by name.
261 private static class ActionRefComparator implements Comparator<ActionRef> {
263 public static final ActionRefComparator INSTANCE = new ActionRefComparator();
266 public int compare(ActionRef arg0, ActionRef arg1) {
267 return ComparisonChain.start()
268 .compare(arg0.getOrder(), arg1.getOrder(), Ordering.natural().nullsLast())
269 .compare(arg0.getName().getValue(), arg1.getName().getValue(), Ordering.natural().nullsLast())
275 private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
276 Direction direction, int priority) {
278 * Create the ordered action list. The implicit action is "allow", and
279 * is therefore always in the list
281 * TODO: revisit implicit vs. default for "allow" TODO: look into
282 * incorporating operational policy for actions
285 // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
286 // referencing in sort
287 List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
288 if (rule.getActionRef() != null) {
290 * Pre-sort by references using order, then name
292 List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
293 Collections.sort(arl, ActionRefComparator.INSTANCE);
295 for (ActionRef actionRule : arl) {
296 ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
297 if (actionInstance == null) {
298 // XXX TODO fail the match and raise an exception
299 LOG.warn("Action instance {} not found", actionRule.getName().getValue());
302 Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
303 if (action == null) {
304 // XXX TODO fail the match and raise an exception
305 LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
309 Map<String, Object> params = new HashMap<>();
310 if (actionInstance.getParameterValue() != null) {
311 for (ParameterValue v : actionInstance.getParameterValue()) {
312 if (v.getName() == null)
314 if (v.getIntValue() != null) {
315 params.put(v.getName().getValue(), v.getIntValue());
316 } else if (v.getStringValue() != null) {
317 params.put(v.getName().getValue(), v.getStringValue());
322 * Convert the GBP Action to one or more OpenFlow Actions
324 actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements);
327 Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
328 actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
331 Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
332 Set<ClassifierDefinitionId> classifiers = new HashSet<>();
333 for (ClassifierRef cr : rule.getClassifierRef()) {
334 if (cr.getDirection() != null && !cr.getDirection().equals(Direction.Bidirectional)
335 && !cr.getDirection().equals(direction)) {
339 // XXX - TODO - implement connection tracking (requires openflow
340 // extension and data plane support - in 2.4. Will need to handle
341 // case where we are working with mix of nodes.
343 ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
345 // XXX TODO fail the match and raise an exception
346 LOG.warn("Classifier instance {} not found", cr.getName().getValue());
349 Classifier cfier = SubjectFeatures.getClassifier(ci.getClassifierDefinitionId());
351 // XXX TODO fail the match and raise an exception
352 LOG.warn("Classifier definition {} not found", ci.getClassifierDefinitionId().getValue());
355 classifiers.add(new ClassifierDefinitionId(ci.getClassifierDefinitionId()));
356 for (ParameterValue v : ci.getParameterValue()) {
358 if (v.getIntValue() != null) {
359 paramsFromClassifier.put(v.getName().getValue(), v);
360 } else if (v.getStringValue() != null) {
361 paramsFromClassifier.put(v.getName().getValue(), v);
362 } else if (v.getRangeValue() != null) {
363 paramsFromClassifier.put(v.getName().getValue(), v);
367 List<Map<String, ParameterValue>> derivedParamsByName = ParamDerivator.ETHER_TYPE_DERIVATOR.deriveParameter(paramsFromClassifier);
369 for (Map<String, ParameterValue> params : derivedParamsByName) {
370 for (ClassifierDefinitionId clDefId : classifiers) {
371 Classifier classifier = SubjectFeatures.getClassifier(clDefId);
372 StringBuilder idb = new StringBuilder();
373 // XXX - TODO - implement connection tracking (requires openflow
374 // extension and data plane support - in 2.4. Will need to handle
375 // case where we are working with mix of nodes.
377 MatchBuilder baseMatch = new MatchBuilder();
378 if (direction.equals(Direction.In)) {
379 idb.append(cgPair.sepg)
381 .append(cgPair.scgId)
385 .append(cgPair.dcgId)
388 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.sepg)),
389 RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.scgId)),
390 RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.depg)),
391 RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.dcgId)));
393 idb.append(cgPair.depg)
395 .append(cgPair.dcgId)
399 .append(cgPair.scgId)
402 addNxRegMatch(baseMatch, RegMatch.of(NxmNxReg0.class, Long.valueOf(cgPair.depg)),
403 RegMatch.of(NxmNxReg1.class, Long.valueOf(cgPair.dcgId)),
404 RegMatch.of(NxmNxReg2.class, Long.valueOf(cgPair.sepg)),
405 RegMatch.of(NxmNxReg3.class, Long.valueOf(cgPair.scgId)));
408 List<MatchBuilder> matches = new ArrayList<>();
409 matches.add(baseMatch);
411 ClassificationResult result = classifier.updateMatch(matches, params);
412 if (!result.isSuccessfull()) {
413 // TODO consider different handling.
414 throw new IllegalArgumentException(result.getErrorMessage());
416 String baseId = idb.toString();
417 FlowBuilder flow = base().setPriority(Integer.valueOf(priority));
418 for (MatchBuilder match : result.getMatchBuilders()) {
419 Match m = match.build();
420 FlowId flowId = new FlowId(baseId + "|" + m.toString());
423 .setPriority(Integer.valueOf(priority))
424 .setInstructions(instructions(applyActionIns(actionBuilderList)));
425 flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build());
432 private static class CgPair {
434 private final int sepg;
435 private final int depg;
436 private final int scgId;
437 private final int dcgId;
439 public CgPair(int sepg, int depg, int scgId, int dcgId) {
448 public int hashCode() {
449 final int prime = 31;
451 result = prime * result + dcgId;
452 result = prime * result + depg;
453 result = prime * result + scgId;
454 result = prime * result + sepg;
459 public boolean equals(Object obj) {
464 if (getClass() != obj.getClass())
466 CgPair other = (CgPair) obj;
467 if (dcgId != other.dcgId)
469 if (depg != other.depg)
471 if (scgId != other.scgId)
473 if (sepg != other.sepg)
479 public class NetworkElements {
483 EndpointFwdCtxOrdinals srcOrds;
484 EndpointFwdCtxOrdinals dstOrds;
486 public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception {
489 this.nodeId = nodeId;
490 this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src);
491 this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst);
496 public EndpointFwdCtxOrdinals getSrcOrds() {
502 public EndpointFwdCtxOrdinals getDstOrds() {
507 public Endpoint getSrc() {
512 public Endpoint getDst() {
517 public NodeId getNodeId() {