7e85e0bb5bd833ec8ff76769f6981ea4f909a983
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / PCMMGateReqBuilder.java
1 /*
2  * Copyright (c) 2015 CableLabs 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.controller.packetcable.provider;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12
13 import com.google.common.collect.Lists;
14 import java.net.Inet4Address;
15 import java.net.Inet6Address;
16 import java.net.InetAddress;
17 import java.net.UnknownHostException;
18 import java.util.List;
19 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.ServiceFlowDirection;
20 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.TosByte;
21 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.ccap.attributes.AmId;
22 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.classifier.attributes.classifiers.ClassifierContainer;
23 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.classifier.attributes.classifiers.classifier.container.ClassifierChoice;
24 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.classifier.attributes.classifiers.classifier.container.classifier.choice.ExtClassifierChoice;
25 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.classifier.attributes.classifiers.classifier.container.classifier.choice.Ipv6ClassifierChoice;
26 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.classifier.attributes.classifiers.classifier.container.classifier.choice.QosClassifierChoice;
27 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.pcmm.qos.classifier.Classifier;
28 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.pcmm.qos.ext.classifier.ExtClassifier;
29 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.pcmm.qos.gate.spec.GateSpec;
30 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.pcmm.qos.ipv6.classifier.Ipv6Classifier;
31 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161017.pcmm.qos.traffic.profile.TrafficProfile;
32 import org.pcmm.gates.IClassifier;
33 import org.pcmm.gates.IClassifier.Protocol;
34 import org.pcmm.gates.IExtendedClassifier;
35 import org.pcmm.gates.IExtendedClassifier.ActivationState;
36 import org.pcmm.gates.IGateSpec.Direction;
37 import org.pcmm.gates.IIPv6Classifier.FlowLabel;
38 import org.pcmm.gates.ITrafficProfile;
39 import org.pcmm.gates.impl.AMID;
40 import org.pcmm.gates.impl.DOCSISServiceClassNameTrafficProfile;
41 import org.pcmm.gates.impl.GateID;
42 import org.pcmm.gates.impl.GateState;
43 import org.pcmm.gates.impl.GateTimeInfo;
44 import org.pcmm.gates.impl.GateUsageInfo;
45 import org.pcmm.gates.impl.PCMMError;
46 import org.pcmm.gates.impl.PCMMGateReq;
47 import org.pcmm.gates.impl.SubscriberID;
48 import org.pcmm.gates.impl.TransactionID;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 /**
53  * Build PCMM gate requests from API QoS Gate objects
54  */
55 public class PCMMGateReqBuilder {
56
57     private final Logger logger = LoggerFactory.getLogger(PCMMGateReqBuilder.class);
58
59     private GateID gateID = null;
60     private AMID amid = null;
61     private SubscriberID subscriberID = null;
62     private TransactionID transactionID = null;
63     private org.pcmm.gates.impl.GateSpec gateSpec = null;
64     private ITrafficProfile trafficProfile = null;
65     private final List<IClassifier> classifiers = Lists.newArrayListWithExpectedSize(4);
66     private PCMMError error = null;
67     private GateState gateState = null;
68     private GateTimeInfo gateTimeInfo = null;
69     private GateUsageInfo gateUsageInfo = null;
70
71     public PCMMGateReq build() {
72         return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers,
73                 gateID, error, gateState, gateTimeInfo, gateUsageInfo);
74     }
75
76     public void setAmId(final AmId qosAmId) {
77         amid = new AMID(qosAmId.getAmType().shortValue(), qosAmId.getAmTag().shortValue());
78     }
79
80     public void setSubscriberId(final InetAddress qosSubId) {
81         subscriberID = new SubscriberID(qosSubId);
82     }
83
84     public void setGateSpec(final GateSpec qosGateSpec, final ServiceFlowDirection scnDirection) {
85
86         final ServiceFlowDirection qosDir;
87         if (scnDirection != null) {
88             qosDir = scnDirection;
89         } else {
90             if (qosGateSpec.getDirection() != null) {
91                 qosDir = qosGateSpec.getDirection();
92             } else {
93                 // TODO - determine if this is a valid default value
94                 qosDir = ServiceFlowDirection.Ds;
95             }
96         }
97
98         final Direction gateDir;
99         if (qosDir == ServiceFlowDirection.Ds) {
100             gateDir = Direction.DOWNSTREAM;
101         } else {
102             gateDir = Direction.UPSTREAM;
103         }
104
105         // DSCP/TOS Overwrite
106         final byte dscptos;
107         final byte gateTosMask;
108
109         final TosByte tosOverwrite = qosGateSpec.getDscpTosOverwrite();
110         if (tosOverwrite != null) {
111             dscptos = 1;
112             TosByte tosMask = qosGateSpec.getDscpTosMask();
113             if (tosMask != null) {
114                 gateTosMask = tosMask.getValue().byteValue();
115             } else {
116                 gateTosMask = (byte) 0xff;
117             }
118         } else {
119             // TODO - These values appear to be required
120             dscptos = 0;
121             gateTosMask = 0;
122         }
123         gateSpec = new org.pcmm.gates.impl.GateSpec(gateDir, dscptos, gateTosMask);
124     }
125
126     public void setTrafficProfile(final TrafficProfile qosTrafficProfile) {
127         if (qosTrafficProfile.getServiceClassName() != null) {
128             trafficProfile =
129                     new DOCSISServiceClassNameTrafficProfile(qosTrafficProfile.getServiceClassName().getValue());
130         }
131     }
132
133     private InetAddress getByName(final String ipAddressStr) {
134         try {
135             return InetAddress.getByName(ipAddressStr);
136         } catch (UnknownHostException e) {
137             logger.error(e.getMessage());
138         }
139         return null;
140     }
141
142     public void setClassifiers(final List<ClassifierContainer> classifiers) {
143         checkNotNull(classifiers);
144
145         for (ClassifierContainer container : classifiers) {
146             final ClassifierChoice choice = container.getClassifierChoice();
147             final Short index = container.getClassifierId();
148
149             if (choice instanceof QosClassifierChoice) {
150                 addClassifier(index, ((QosClassifierChoice) choice).getClassifier());
151             }
152             else if (choice instanceof ExtClassifierChoice) {
153                 addExtClassifier(index, ((ExtClassifierChoice) choice).getExtClassifier());
154             }
155             else if (choice instanceof Ipv6ClassifierChoice) {
156                 addIpv6Classifier(index, ((Ipv6ClassifierChoice) choice).getIpv6Classifier());
157             }
158             else {
159                 throw new IllegalStateException("Unknown ClassifierChoice: " + choice);
160             }
161         }
162     }
163
164     private void addClassifier(final Short index,final Classifier qosClassifier) {
165         // TODO - try and make these variables immutable
166         Protocol protocol = null;
167         byte tosOverwrite = 0;
168         byte tosMask = (byte)0x0;
169         short srcPort = (short) 0;
170         short dstPort = (short) 0;
171         //byte priority = (byte) 64;
172         byte priority = (byte) (64+index);
173
174         // Legacy classifier
175
176         // Protocol -- zero is match any
177         if (qosClassifier.getProtocol() != null) {
178             protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
179         } else {
180             protocol = Protocol.NONE;
181         }
182
183         // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything)
184
185         Inet4Address srcAddress = (Inet4Address) getByName("0.0.0.0");
186
187         if (qosClassifier.getSrcIp() != null) {
188             srcAddress = (Inet4Address) getByName(qosClassifier.getSrcIp().getValue());
189         }
190
191         Inet4Address dstAddress = (Inet4Address) getByName("0.0.0.0");
192
193         if (qosClassifier.getDstIp() != null) {
194             dstAddress = (Inet4Address) getByName(qosClassifier.getDstIp().getValue());
195         }
196
197
198         if (qosClassifier.getSrcPort() != null) {
199             srcPort = qosClassifier.getSrcPort().getValue().shortValue();
200         }
201         if (qosClassifier.getDstPort() != null) {
202             dstPort = qosClassifier.getDstPort().getValue().shortValue();
203         }
204         if (qosClassifier.getTosByte() != null) {
205             tosOverwrite = qosClassifier.getTosByte().getValue().byteValue();
206             if (qosClassifier.getTosMask() != null) {
207                 tosMask = qosClassifier.getTosMask().getValue().byteValue();
208             } else {
209                 // set default TOS mask
210                 tosMask = (byte) 0xff;
211             }
212         }
213         // push the classifier to the gate request
214         classifiers.add(new org.pcmm.gates.impl.Classifier(protocol, tosOverwrite, tosMask, srcAddress, dstAddress, srcPort,
215                 dstPort, priority));
216     }
217
218     private void addExtClassifier(final Short index, final ExtClassifier qosExtClassifier) {
219         // Extended classifier
220         final byte priority = (byte) (index+64);
221         final ActivationState activationState = ActivationState.ACTIVE;
222         // Protocol -- zero is match any
223         final Protocol protocol;
224         if (qosExtClassifier.getProtocol() != null) {
225             protocol = Protocol.valueOf(qosExtClassifier.getProtocol().getValue().shortValue());
226         } else {
227             protocol = Protocol.NONE;
228         }
229
230         // default source port range must be set to match any even if qosExtClassifier has no range
231         // match any port range is 0-65535, NOT 0-0
232         // TODO - try to make these two variables immutable
233         short srcStartPort = (short) 0;
234         short srcEndPort = (short) 65535;
235         if (qosExtClassifier.getSrcPortStart() != null) {
236             srcStartPort = qosExtClassifier.getSrcPortStart().getValue().shortValue();
237             srcEndPort = srcStartPort;
238             if (qosExtClassifier.getSrcPortEnd() != null) {
239                 srcEndPort = qosExtClassifier.getSrcPortEnd().getValue().shortValue();
240             }
241             if ((int)(srcStartPort & 0xffff) > (int) (srcEndPort & 0xffff)) {
242                 logger.warn("Start port %d > End port %d in ext-classifier source port range -- forcing to same",
243                         srcStartPort, srcEndPort);
244                 srcEndPort = srcStartPort;
245             }
246         }
247         // default destination port range must be set to match any even if qosExtClassifier has no range
248         // match any port range is 0-65535, NOT 0-0
249         // TODO - try to make these two variables immutable
250         short dstStartPort = (short) 0;
251         short dstEndPort = (short) 65535;
252         if (qosExtClassifier.getDstPortStart() != null) {
253             dstStartPort = qosExtClassifier.getDstPortStart().getValue().shortValue();
254             dstEndPort = dstStartPort;
255             if (qosExtClassifier.getDstPortEnd() != null) {
256                 dstEndPort = qosExtClassifier.getDstPortEnd().getValue().shortValue();
257             }
258             if ((int)(dstStartPort & 0xffff) > (int)(dstEndPort & 0xffff)) {
259                 logger.warn("Start port %d > End port %d in ext-classifier destination port range -- forcing to same",
260                         dstStartPort, dstEndPort);
261                 dstEndPort = dstStartPort;
262             }
263         }
264
265         // DSCP/TOP byte
266         // TODO - try to make these two variables immutable
267         byte tosOverwrite = 0;
268         byte tosMask = (byte)0x00;
269         if (qosExtClassifier.getTosByte() != null) {
270             // OR in the DSCP/TOS enable bit 0x01
271             tosOverwrite = (byte) (qosExtClassifier.getTosByte().getValue().byteValue() | 0x01);
272             if (qosExtClassifier.getTosMask() != null) {
273                 tosMask = qosExtClassifier.getTosMask().getValue().byteValue();
274             } else {
275                 // set default TOS mask
276                 tosMask = (byte) 0xff;
277             }
278         }
279
280         // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything) and mask is 255.255.255.255 by default
281         Inet4Address srcIpAddr = (Inet4Address) getByName("0.0.0.0");
282
283         if (qosExtClassifier.getSrcIp() != null) {
284             srcIpAddr = getInet4Address(qosExtClassifier.getSrcIp());
285         }
286
287         Inet4Address dstIpAddr = (Inet4Address) getByName("0.0.0.0");
288         if (qosExtClassifier.getDstIp() != null) {
289             dstIpAddr = getInet4Address(qosExtClassifier.getDstIp());
290         }
291
292         //mask
293         Inet4Address srcIpMask = (Inet4Address) getByName("255.255.255.255");
294         if (qosExtClassifier.getSrcIpMask() != null) {
295             srcIpMask = getInet4Address(qosExtClassifier.getSrcIpMask());
296         }
297
298         Inet4Address dstIpMask = (Inet4Address) getByName("255.255.255.255");
299         if (qosExtClassifier.getDstIpMask() != null) {
300             dstIpMask = getInet4Address(qosExtClassifier.getDstIpMask());
301         }
302
303         // TODO - find out what the classifier ID should really be. It was never getting set previously
304         final short classifierId = (short)index;
305
306         // TODO - find out what the action value should really be. It was never getting set previously
307         final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
308
309         // push the extended classifier to the gate request
310         classifiers.add(new org.pcmm.gates.impl.ExtendedClassifier(protocol, tosOverwrite, tosMask,
311                 srcIpAddr, dstIpAddr,
312                 srcStartPort, dstStartPort, priority, srcIpMask, dstIpMask, srcEndPort, dstEndPort, classifierId, activationState,
313                 action));
314     }
315
316     private Inet4Address getInet4Address(
317             final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address address) {
318         if (address != null) {
319             final InetAddress out = getByName(address.getValue());
320             if (out != null && out instanceof Inet4Address) {
321                 return (Inet4Address) out;
322             }
323         }
324         return null;
325     }
326
327     private void addIpv6Classifier(final Short index, final Ipv6Classifier qosIpv6Classifier) {
328         // Next Header
329         final short nextHdr;
330         if (qosIpv6Classifier.getNextHdr() != null) {
331             nextHdr = qosIpv6Classifier.getNextHdr().getValue().shortValue();
332         }
333         // default: match any nextHdr is 256 because nextHdr 0 is Hop-by-Hop option
334         else {
335             nextHdr = (short) 256;
336         }
337
338         // Source IPv6 address & prefix len
339         // TODO - try to make these two variables immutable
340         byte srcPrefixLen = (byte) 128;
341         Inet6Address srcAddress = (Inet6Address) getByName("0::0");
342
343         if (qosIpv6Classifier.getSrcIp6() != null) {
344             String[] parts = qosIpv6Classifier.getSrcIp6().getValue().split("/");
345             String Ipv6AddressStr = parts[0];
346             srcAddress = (Inet6Address) getByName(Ipv6AddressStr);
347             if (parts.length > 1) {
348                 srcPrefixLen = (byte) Integer.parseInt(parts[1]);
349             } else {
350                 srcPrefixLen = (byte) 128;
351             }
352
353         }
354
355         // TODO - try to make these two variables immutable
356         Inet6Address dstAddress = (Inet6Address) getByName("0::0");
357
358         byte dstPrefLen = (byte) 128;
359         // Destination IPv6 address & prefix len
360         if (qosIpv6Classifier.getDstIp6() != null) {
361             final String[] parts = qosIpv6Classifier.getDstIp6().getValue().split("/");
362             final String Ipv6AddressStr = parts[0];
363             dstAddress = (Inet6Address)getByName(Ipv6AddressStr);
364             if (parts.length > 1) dstPrefLen = (byte) Integer.parseInt(parts[1]);
365             else dstPrefLen = (byte) 128;
366         }
367
368         // default source port range must be set to match any -- even if qosExtClassifier has no range value
369         // match any port range is 0-65535, NOT 0-0
370         short srcPortBegin = (short) 0;
371         short srcPortEnd = (short) 65535;
372         if (qosIpv6Classifier.getSrcPortStart() != null) {
373             srcPortBegin = qosIpv6Classifier.getSrcPortStart().getValue().shortValue();
374             srcPortEnd = srcPortBegin;
375             if (qosIpv6Classifier.getSrcPortEnd() != null) {
376                 srcPortEnd = qosIpv6Classifier.getSrcPortEnd().getValue().shortValue();
377             }
378             if ((int)(srcPortBegin & 0xffff) > (int)(srcPortEnd & 0xffff)) {
379                 logger.warn("Start port %d > End port %d in ipv6-classifier source port range -- forcing to same",
380                         srcPortBegin, srcPortEnd);
381                 srcPortEnd = srcPortBegin;
382             }
383         }
384
385         // default destination port range must be set to match any -- even if qosExtClassifier has no range value
386         // match any port range is 0-65535, NOT 0-0
387         short dstPortBegin = (short) 0;
388         short dstPortEnd = (short) 65535;
389         if (qosIpv6Classifier.getDstPortStart() != null) {
390             dstPortBegin = qosIpv6Classifier.getDstPortStart().getValue().shortValue();
391             dstPortEnd = dstPortBegin;
392             if (qosIpv6Classifier.getDstPortEnd() != null) {
393                 dstPortEnd = qosIpv6Classifier.getDstPortEnd().getValue().shortValue();
394             }
395             if ( (int)(dstPortBegin & 0xffff) > (int)(dstPortEnd & 0xffff)) {
396                 logger.warn("Start port %d > End port %d in ipv6-classifier destination port range -- forcing to same",
397                         dstPortBegin, dstPortEnd);
398                 dstPortEnd = dstPortBegin;
399             }
400         }
401
402         final byte tcLow;
403         if (qosIpv6Classifier.getTcLow() != null)
404             tcLow = qosIpv6Classifier.getTcLow().getValue().byteValue();
405         else tcLow = (byte) 0x00;
406
407         final byte tcHigh;
408         if (qosIpv6Classifier.getTcHigh() != null)
409             tcHigh = qosIpv6Classifier.getTcHigh().getValue().byteValue();
410         else tcHigh = (byte) 0x00;
411
412         final byte tcMask;
413         if (qosIpv6Classifier.getTcHigh() != null)
414             tcMask = qosIpv6Classifier.getTcHigh().getValue().byteValue();
415         else if (qosIpv6Classifier.getTcLow() != null) tcMask = (byte) 0xff;
416         else tcMask = (byte) 0x00;
417
418         FlowLabel flowLabelFlag = FlowLabel.IRRELEVANT;
419         int flowLabelId = 0;
420
421         if (qosIpv6Classifier.getFlowLabel() != null) {
422             flowLabelFlag = FlowLabel.VALID;
423             flowLabelId = qosIpv6Classifier.getFlowLabel().intValue();
424         }
425
426
427         // TODO - find out what the classifier ID should really be. It was never getting set previously
428         final short classifierId = (short)index;
429
430         // TODO - find out what the action value should really be. It was never getting set previously
431         final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
432
433         // push the IPv6 classifier to the gate request
434         classifiers.add(
435                 new org.pcmm.gates.impl.IPv6Classifier(srcAddress, dstAddress, srcPortBegin, dstPortBegin, (byte) (index+64),
436                         srcPortEnd, dstPortEnd, classifierId, ActivationState.ACTIVE, action, flowLabelFlag, tcLow,
437                         tcHigh, tcMask, flowLabelId, nextHdr, srcPrefixLen, dstPrefLen));
438     }
439 }