Added range type to subject-feature-definition/parameter
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / PolicyEnforcer.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
10
11 import java.util.Collections;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import javax.annotation.concurrent.Immutable;
19
20 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
21 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
22 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
23 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
24 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
25 import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
26 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
27 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
28 import org.opendaylight.groupbasedpolicy.resolver.Policy;
29 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
30 import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
58
59 /**
60  * Manage the table that enforces policy on the traffic.  Traffic is denied
61  * unless specifically allowed by policy
62  * @author readams
63  */
64 public class PolicyEnforcer extends FlowTable {
65     protected static final Logger LOG =
66             LoggerFactory.getLogger(PolicyEnforcer.class);
67
68     public static final short TABLE_ID = 3;
69
70     public PolicyEnforcer(OfTable.OfTableCtx ctx) {
71         super(ctx);
72     }
73
74     @Override
75     public short getTableId() {
76         return TABLE_ID;
77     }
78
79     @Override
80     public void sync(ReadWriteTransaction t, InstanceIdentifier<Table> tiid,
81                      Map<String, FlowCtx> flowMap, NodeId nodeId, 
82                      PolicyInfo policyInfo, Dirty dirty)
83                              throws Exception {
84         dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
85         allowFromTunnel(t, tiid, flowMap, nodeId);
86
87         HashSet<CgPair> visitedPairs = new HashSet<>();
88
89         for (EgKey sepg : ctx.epManager.getGroupsForNode(nodeId)) {
90             // Allow traffic within the same endpoint group if the policy
91             // specifies
92             IndexedTenant tenant = 
93                     ctx.policyResolver.getTenant(sepg.getTenantId());
94             EndpointGroup group = 
95                     tenant.getEndpointGroup(sepg.getEgId());
96             IntraGroupPolicy igp = group.getIntraGroupPolicy();
97             int sepgId = 
98                     ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
99                                                         sepg.getEgId());
100             if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
101                 allowSameEpg(t, tiid, flowMap, nodeId, sepgId);
102             }
103
104             for (Endpoint src : ctx.epManager.getEPsForNode(nodeId, sepg)) {
105                 if (src.getTenant() == null || src.getEndpointGroup() == null)
106                     continue;
107                 
108                 List<ConditionName> conds = 
109                         ctx.epManager.getCondsForEndpoint(src);
110                 ConditionGroup scg = policyInfo.getEgCondGroup(sepg, conds);
111                 int scgId = ctx.policyManager.getCondGroupOrdinal(scg);
112                 
113                 Set<EgKey> peers = policyInfo.getPeers(sepg);
114                 for (EgKey depg : peers) {
115                     int depgId = 
116                             ctx.policyManager.getContextOrdinal(depg.getTenantId(), 
117                                                                 depg.getEgId());
118                 
119                     for (Endpoint dst : ctx.epManager.getEndpointsForGroup(depg)) {
120                 
121                         conds = ctx.epManager.getCondsForEndpoint(dst);
122                         ConditionGroup dcg = 
123                                 policyInfo.getEgCondGroup(new EgKey(dst.getTenant(), 
124                                                                     dst.getEndpointGroup()),
125                                                           conds);
126                         int dcgId = ctx.policyManager.getCondGroupOrdinal(dcg);
127                         
128                         CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
129                         if (visitedPairs.contains(p)) continue;
130                         visitedPairs.add(p);
131                         syncPolicy(t, tiid, flowMap, nodeId, policyInfo, 
132                                    p, depg, sepg, dcg, scg);
133                 
134                         p = new CgPair(sepgId, depgId, scgId, dcgId);
135                         if (visitedPairs.contains(p)) continue;
136                         visitedPairs.add(p);
137                         syncPolicy(t, tiid, flowMap, nodeId, policyInfo, 
138                                    p, sepg, depg, scg, dcg);
139                         
140                     }
141                 }
142             }
143         }
144     }
145     
146     private void allowSameEpg(ReadWriteTransaction t, 
147                               InstanceIdentifier<Table> tiid,
148                               Map<String, FlowCtx> flowMap, NodeId nodeId,
149                               int sepgId) {
150         FlowId flowId = new FlowId(new StringBuilder()
151             .append("intraallow|")
152             .append(sepgId).toString());
153         if (visit(flowMap, flowId.getValue())) {
154             MatchBuilder mb = new MatchBuilder();
155             addNxRegMatch(mb, 
156                           RegMatch.of(NxmNxReg0.class,Long.valueOf(sepgId)),
157                           RegMatch.of(NxmNxReg2.class,Long.valueOf(sepgId)));
158             FlowBuilder flow = base()
159                 .setId(flowId)
160                 .setMatch(mb.build())
161                 .setPriority(65000)
162                 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
163             writeFlow(t, tiid, flow.build());
164         }
165     }
166     
167     private void allowFromTunnel(ReadWriteTransaction t, 
168                                  InstanceIdentifier<Table> tiid,
169                                  Map<String, FlowCtx> flowMap, NodeId nodeId) {
170         NodeConnectorId tunPort =
171                 ctx.switchManager.getTunnelPort(nodeId);
172         if (tunPort == null) return;
173
174         FlowId flowId = new FlowId("tunnelallow");
175         if (visit(flowMap, flowId.getValue())) {
176             MatchBuilder mb = new MatchBuilder()
177                 .setInPort(tunPort);
178             addNxRegMatch(mb, 
179                           RegMatch.of(NxmNxReg1.class,Long.valueOf(0xffffff)));
180             FlowBuilder flow = base()
181                 .setId(flowId)
182                 .setMatch(mb.build())
183                 .setPriority(65000)
184                 .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
185             writeFlow(t, tiid, flow.build());
186         }
187     }
188     
189     private void syncPolicy(ReadWriteTransaction t, 
190                             InstanceIdentifier<Table> tiid,
191                             Map<String, FlowCtx> flowMap, NodeId nodeId,
192                             PolicyInfo policyInfo, 
193                             CgPair p, EgKey sepg, EgKey depg,
194                             ConditionGroup scg, ConditionGroup dcg) 
195                              throws Exception {
196         // XXX - TODO raise an exception for rules between the same
197         // endpoint group that are asymmetric
198         Policy policy = policyInfo.getPolicy(sepg, depg);
199         List<RuleGroup> rgs = policy.getRules(scg, dcg);
200         
201         int priority = 65000;
202         for (RuleGroup rg : rgs) {
203             TenantId tenantId = rg.getContractTenant().getId();
204             IndexedTenant tenant = ctx.policyResolver.getTenant(tenantId); 
205             for (Rule r : rg.getRules()) {
206                 syncDirection(t, tiid, flowMap, nodeId, tenant,
207                                     p, r, Direction.In, priority);
208                 syncDirection(t, tiid, flowMap, nodeId, tenant,
209                                     p, r, Direction.Out, priority);
210                 
211                 priority -= 1;
212             }
213         }
214     }
215     
216     private void syncDirection(ReadWriteTransaction t, 
217                                InstanceIdentifier<Table> tiid,
218                                Map<String, FlowCtx> flowMap, NodeId nodeId,
219                                IndexedTenant contractTenant,
220                                CgPair p, Rule r, Direction d, int priority) {
221         for (ClassifierRef cr : r.getClassifierRef()) {
222             if (cr.getDirection() != null && 
223                 !cr.getDirection().equals(Direction.Bidirectional) && 
224                 !cr.getDirection().equals(d))
225                 continue;
226             
227             StringBuilder idb = new StringBuilder();
228             // XXX - TODO - implement connection tracking (requires openflow 
229             // extension and data plane support)
230
231             MatchBuilder baseMatch = new MatchBuilder();
232
233             if (d.equals(Direction.In)) {
234                 idb.append(p.sepg)
235                     .append("|")
236                     .append(p.scgId)
237                     .append("|")
238                     .append(p.depg)
239                     .append("|")
240                     .append(p.dcgId)
241                     .append("|")
242                     .append(priority);
243                 addNxRegMatch(baseMatch, 
244                               RegMatch.of(NxmNxReg0.class,Long.valueOf(p.sepg)),
245                               RegMatch.of(NxmNxReg1.class,Long.valueOf(p.scgId)),
246                               RegMatch.of(NxmNxReg2.class,Long.valueOf(p.depg)),
247                               RegMatch.of(NxmNxReg3.class,Long.valueOf(p.dcgId)));
248             } else {
249                 idb.append(p.depg)
250                     .append("|")
251                     .append(p.dcgId)
252                     .append("|")
253                     .append(p.sepg)
254                     .append("|")
255                     .append(p.scgId)
256                     .append("|")
257                     .append(priority);                
258                 addNxRegMatch(baseMatch, 
259                               RegMatch.of(NxmNxReg0.class,Long.valueOf(p.depg)),
260                               RegMatch.of(NxmNxReg1.class,Long.valueOf(p.dcgId)),
261                               RegMatch.of(NxmNxReg2.class,Long.valueOf(p.sepg)),
262                               RegMatch.of(NxmNxReg3.class,Long.valueOf(p.scgId)));
263             }
264
265
266             ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
267             if (ci == null) {
268                 // XXX TODO fail the match and raise an exception
269                 LOG.warn("Classifier instance {} not found", 
270                          cr.getName().getValue());
271                 return;
272             }
273             Classifier cfier = SubjectFeatures
274                     .getClassifier(ci.getClassifierDefinitionId());
275             if (cfier == null) {
276                 // XXX TODO fail the match and raise an exception
277                 LOG.warn("Classifier definition {} not found", 
278                          ci.getClassifierDefinitionId().getValue());
279                 return;
280             }
281
282             List<MatchBuilder> matches = Collections.singletonList(baseMatch);
283             Map<String,Object> params = new HashMap<>();
284             for (ParameterValue v : ci.getParameterValue()) {
285                 if (v.getName() == null) continue;
286                 if (v.getIntValue() != null) {
287                     params.put(v.getName().getValue(), v.getIntValue());
288                 } else if (v.getStringValue() != null) {
289                     params.put(v.getName().getValue(), v.getStringValue());
290                 }
291             }
292             
293             matches = cfier.updateMatch(matches, params);
294             String baseId = idb.toString();
295             FlowBuilder flow = base()
296                     .setPriority(Integer.valueOf(priority));
297             for (MatchBuilder match : matches) {
298                 Match m = match.build();
299                 FlowId flowId = new FlowId(baseId + "|" + m.toString());
300                 if (visit(flowMap, flowId.getValue())) {
301                     flow.setMatch(m)
302                         .setId(flowId)
303                         .setPriority(Integer.valueOf(priority))
304                         .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
305                     writeFlow(t, tiid, flow.build());
306                 }
307             }
308         } 
309
310     }
311
312     @Immutable
313     private static class CgPair {
314         private final int sepg;
315         private final int depg;
316         private final int scgId;
317         private final int dcgId;
318         
319         public CgPair(int sepg, int depg, int scgId, int dcgId) {
320             super();
321             this.sepg = sepg;
322             this.depg = depg;
323             this.scgId = scgId;
324             this.dcgId = dcgId;
325         }
326
327         @Override
328         public int hashCode() {
329             final int prime = 31;
330             int result = 1;
331             result = prime * result + dcgId;
332             result = prime * result + depg;
333             result = prime * result + scgId;
334             result = prime * result + sepg;
335             return result;
336         }
337
338         @Override
339         public boolean equals(Object obj) {
340             if (this == obj)
341                 return true;
342             if (obj == null)
343                 return false;
344             if (getClass() != obj.getClass())
345                 return false;
346             CgPair other = (CgPair) obj;
347             if (dcgId != other.dcgId)
348                 return false;
349             if (depg != other.depg)
350                 return false;
351             if (scgId != other.scgId)
352                 return false;
353             if (sepg != other.sepg)
354                 return false;
355             return true;
356         }
357     }
358 }