Solved Bug 6302-
[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.rev161107.ServiceFlowDirection;
20 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.TosByte;
21 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.attributes.AmId;
22 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.classifier.attributes.classifiers.ClassifierContainer;
23 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.classifier.attributes.classifiers.classifier.container.ClassifierChoice;
24 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.classifier.attributes.classifiers.classifier.container.classifier.choice.ExtClassifierChoice;
25 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.classifier.attributes.classifiers.classifier.container.classifier.choice.Ipv6ClassifierChoice;
26 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.classifier.attributes.classifiers.classifier.container.classifier.choice.QosClassifierChoice;
27 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.classifier.Classifier;
28 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.ext.classifier.ExtClassifier;
29 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gate.spec.GateSpec;
30 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.ipv6.classifier.Ipv6Classifier;
31 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.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
172         // Legacy classifier
173
174         // Protocol -- zero is match any
175         if (qosClassifier.getProtocol() != null) {
176             protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
177         } else {
178             protocol = Protocol.NONE;
179         }
180
181         // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything)
182
183         Inet4Address srcAddress = (Inet4Address) getByName("0.0.0.0");
184
185         if (qosClassifier.getSrcIp() != null) {
186             srcAddress = (Inet4Address) getByName(qosClassifier.getSrcIp().getValue());
187         }
188
189         Inet4Address dstAddress = (Inet4Address) getByName("0.0.0.0");
190
191         if (qosClassifier.getDstIp() != null) {
192             dstAddress = (Inet4Address) getByName(qosClassifier.getDstIp().getValue());
193         }
194
195
196         if (qosClassifier.getSrcPort() != null) {
197             srcPort = qosClassifier.getSrcPort().getValue().shortValue();
198         }
199         if (qosClassifier.getDstPort() != null) {
200             dstPort = qosClassifier.getDstPort().getValue().shortValue();
201         }
202         if (qosClassifier.getTosByte() != null) {
203             tosOverwrite = qosClassifier.getTosByte().getValue().byteValue();
204             if (qosClassifier.getTosMask() != null) {
205                 tosMask = qosClassifier.getTosMask().getValue().byteValue();
206             } else {
207                 // set default TOS mask
208                 tosMask = (byte) 0xff;
209             }
210         }
211         //
212         // The packetcable.yang models priority as an uint8 which means the java generated
213         // implementation saves the value in a short, so we mask it back into a byte
214         //
215         byte priority = 64;
216         if (qosClassifier.getPriority() != null) {
217             short result = qosClassifier.getPriority();
218             priority = (byte)(result % 255);
219         }
220
221         // push the classifier to the gate request
222         classifiers.add(new org.pcmm.gates.impl.Classifier(protocol, tosOverwrite, tosMask, srcAddress, dstAddress, srcPort,
223                 dstPort, priority));
224     }
225
226     private void addExtClassifier(final Short index, final ExtClassifier qosExtClassifier) {
227         // Extended classifier
228         final ActivationState activationState = ActivationState.ACTIVE;
229         // Protocol -- zero is match any
230         final Protocol protocol;
231         if (qosExtClassifier.getProtocol() != null) {
232             protocol = Protocol.valueOf(qosExtClassifier.getProtocol().getValue().shortValue());
233         } else {
234             protocol = Protocol.NONE;
235         }
236
237         // default source port range must be set to match any even if qosExtClassifier has no range
238         // match any port range is 0-65535, NOT 0-0
239         // TODO - try to make these two variables immutable
240         short srcStartPort = (short) 0;
241         short srcEndPort = (short) 65535;
242         if (qosExtClassifier.getSrcPortStart() != null) {
243             srcStartPort = qosExtClassifier.getSrcPortStart().getValue().shortValue();
244             srcEndPort = srcStartPort;
245             if (qosExtClassifier.getSrcPortEnd() != null) {
246                 srcEndPort = qosExtClassifier.getSrcPortEnd().getValue().shortValue();
247             }
248             if ((int)(srcStartPort & 0xffff) > (int) (srcEndPort & 0xffff)) {
249                 logger.warn("Start port %d > End port %d in ext-classifier source port range -- forcing to same",
250                         srcStartPort, srcEndPort);
251                 srcEndPort = srcStartPort;
252             }
253         }
254         // default destination port range must be set to match any even if qosExtClassifier has no range
255         // match any port range is 0-65535, NOT 0-0
256         // TODO - try to make these two variables immutable
257         short dstStartPort = (short) 0;
258         short dstEndPort = (short) 65535;
259         if (qosExtClassifier.getDstPortStart() != null) {
260             dstStartPort = qosExtClassifier.getDstPortStart().getValue().shortValue();
261             dstEndPort = dstStartPort;
262             if (qosExtClassifier.getDstPortEnd() != null) {
263                 dstEndPort = qosExtClassifier.getDstPortEnd().getValue().shortValue();
264             }
265             if ((int)(dstStartPort & 0xffff) > (int)(dstEndPort & 0xffff)) {
266                 logger.warn("Start port %d > End port %d in ext-classifier destination port range -- forcing to same",
267                         dstStartPort, dstEndPort);
268                 dstEndPort = dstStartPort;
269             }
270         }
271
272         // DSCP/TOP byte
273         // TODO - try to make these two variables immutable
274         byte tosOverwrite = 0;
275         byte tosMask = (byte)0x00;
276         if (qosExtClassifier.getTosByte() != null) {
277             // OR in the DSCP/TOS enable bit 0x01
278             tosOverwrite = (byte) (qosExtClassifier.getTosByte().getValue().byteValue() | 0x01);
279             if (qosExtClassifier.getTosMask() != null) {
280                 tosMask = qosExtClassifier.getTosMask().getValue().byteValue();
281             } else {
282                 // set default TOS mask
283                 tosMask = (byte) 0xff;
284             }
285         }
286
287         // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything) and mask is 255.255.255.255 by default
288         Inet4Address srcIpAddr = (Inet4Address) getByName("0.0.0.0");
289
290         if (qosExtClassifier.getSrcIp() != null) {
291             srcIpAddr = getInet4Address(qosExtClassifier.getSrcIp());
292         }
293
294         Inet4Address dstIpAddr = (Inet4Address) getByName("0.0.0.0");
295         if (qosExtClassifier.getDstIp() != null) {
296             dstIpAddr = getInet4Address(qosExtClassifier.getDstIp());
297         }
298
299         //mask
300         Inet4Address srcIpMask = (Inet4Address) getByName("255.255.255.255");
301         if (qosExtClassifier.getSrcIpMask() != null) {
302             srcIpMask = getInet4Address(qosExtClassifier.getSrcIpMask());
303         }
304
305         Inet4Address dstIpMask = (Inet4Address) getByName("255.255.255.255");
306         if (qosExtClassifier.getDstIpMask() != null) {
307             dstIpMask = getInet4Address(qosExtClassifier.getDstIpMask());
308         }
309
310         // TODO - find out what the classifier ID should really be. It was never getting set previously
311         final short classifierId = (short)index;
312
313         // TODO - find out what the action value should really be. It was never getting set previously
314         final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
315
316         //
317         // The packetcable.yang models priority as an uint8 which means the java generated
318         // implementation saves the value in a short, so we mask it back into a byte
319         //
320         byte priority = 64;
321         if (qosExtClassifier.getPriority() != null) {
322             short result = qosExtClassifier.getPriority();
323             priority = (byte)(result % 255);
324         }
325
326         // push the extended classifier to the gate request
327         classifiers.add(new org.pcmm.gates.impl.ExtendedClassifier(protocol, tosOverwrite, tosMask,
328                 srcIpAddr, dstIpAddr,
329                 srcStartPort, dstStartPort, priority, srcIpMask, dstIpMask, srcEndPort, dstEndPort, classifierId, activationState,
330                 action));
331     }
332
333     private Inet4Address getInet4Address(
334             final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address address) {
335         if (address != null) {
336             final InetAddress out = getByName(address.getValue());
337             if (out != null && out instanceof Inet4Address) {
338                 return (Inet4Address) out;
339             }
340         }
341         return null;
342     }
343
344     private void addIpv6Classifier(final Short index, final Ipv6Classifier qosIpv6Classifier) {
345         // Next Header
346         final short nextHdr;
347         if (qosIpv6Classifier.getNextHdr() != null) {
348             nextHdr = qosIpv6Classifier.getNextHdr().getValue().shortValue();
349         }
350         // default: match any nextHdr is 256 because nextHdr 0 is Hop-by-Hop option
351         else {
352             nextHdr = (short) 256;
353         }
354
355         // Source IPv6 address & prefix len
356         // TODO - try to make these two variables immutable
357         byte srcPrefixLen = (byte) 128;
358         Inet6Address srcAddress = (Inet6Address) getByName("0::0");
359
360         if (qosIpv6Classifier.getSrcIp6() != null) {
361             String[] parts = qosIpv6Classifier.getSrcIp6().getValue().split("/");
362             String Ipv6AddressStr = parts[0];
363             srcAddress = (Inet6Address) getByName(Ipv6AddressStr);
364             if (parts.length > 1) {
365                 srcPrefixLen = (byte) Integer.parseInt(parts[1]);
366             } else {
367                 srcPrefixLen = (byte) 128;
368             }
369
370         }
371
372         // TODO - try to make these two variables immutable
373         Inet6Address dstAddress = (Inet6Address) getByName("0::0");
374
375         byte dstPrefLen = (byte) 128;
376         // Destination IPv6 address & prefix len
377         if (qosIpv6Classifier.getDstIp6() != null) {
378             final String[] parts = qosIpv6Classifier.getDstIp6().getValue().split("/");
379             final String Ipv6AddressStr = parts[0];
380             dstAddress = (Inet6Address)getByName(Ipv6AddressStr);
381             if (parts.length > 1) dstPrefLen = (byte) Integer.parseInt(parts[1]);
382             else dstPrefLen = (byte) 128;
383         }
384
385         // default source 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 srcPortBegin = (short) 0;
388         short srcPortEnd = (short) 65535;
389         if (qosIpv6Classifier.getSrcPortStart() != null) {
390             srcPortBegin = qosIpv6Classifier.getSrcPortStart().getValue().shortValue();
391             srcPortEnd = srcPortBegin;
392             if (qosIpv6Classifier.getSrcPortEnd() != null) {
393                 srcPortEnd = qosIpv6Classifier.getSrcPortEnd().getValue().shortValue();
394             }
395             if ((int)(srcPortBegin & 0xffff) > (int)(srcPortEnd & 0xffff)) {
396                 logger.warn("Start port %d > End port %d in ipv6-classifier source port range -- forcing to same",
397                         srcPortBegin, srcPortEnd);
398                 srcPortEnd = srcPortBegin;
399             }
400         }
401
402         // default destination port range must be set to match any -- even if qosExtClassifier has no range value
403         // match any port range is 0-65535, NOT 0-0
404         short dstPortBegin = (short) 0;
405         short dstPortEnd = (short) 65535;
406         if (qosIpv6Classifier.getDstPortStart() != null) {
407             dstPortBegin = qosIpv6Classifier.getDstPortStart().getValue().shortValue();
408             dstPortEnd = dstPortBegin;
409             if (qosIpv6Classifier.getDstPortEnd() != null) {
410                 dstPortEnd = qosIpv6Classifier.getDstPortEnd().getValue().shortValue();
411             }
412             if ( (int)(dstPortBegin & 0xffff) > (int)(dstPortEnd & 0xffff)) {
413                 logger.warn("Start port %d > End port %d in ipv6-classifier destination port range -- forcing to same",
414                         dstPortBegin, dstPortEnd);
415                 dstPortEnd = dstPortBegin;
416             }
417         }
418
419         final byte tcLow;
420         if (qosIpv6Classifier.getTcLow() != null)
421             tcLow = qosIpv6Classifier.getTcLow().getValue().byteValue();
422         else tcLow = (byte) 0x00;
423
424         final byte tcHigh;
425         if (qosIpv6Classifier.getTcHigh() != null)
426             tcHigh = qosIpv6Classifier.getTcHigh().getValue().byteValue();
427         else tcHigh = (byte) 0x00;
428
429         final byte tcMask;
430         if (qosIpv6Classifier.getTcHigh() != null)
431             tcMask = qosIpv6Classifier.getTcHigh().getValue().byteValue();
432         else if (qosIpv6Classifier.getTcLow() != null) tcMask = (byte) 0xff;
433         else tcMask = (byte) 0x00;
434
435         FlowLabel flowLabelFlag = FlowLabel.IRRELEVANT;
436         int flowLabelId = 0;
437
438         if (qosIpv6Classifier.getFlowLabel() != null) {
439             flowLabelFlag = FlowLabel.VALID;
440             flowLabelId = qosIpv6Classifier.getFlowLabel().intValue();
441         }
442
443
444         // TODO - find out what the classifier ID should really be. It was never getting set previously
445         final short classifierId = (short)index;
446
447         // TODO - find out what the action value should really be. It was never getting set previously
448         final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
449
450         //
451         // The packetcable.yang models priority as an uint8 which means the java generated
452         // implementation saves the value in a short, so we mask it back into a byte
453         //
454         byte priority = 64;
455         if (qosIpv6Classifier.getPriority() != null) {
456             short result = qosIpv6Classifier.getPriority();
457             priority = (byte)(result % 255);
458         }
459
460         // push the IPv6 classifier to the gate request
461         classifiers.add(
462                 new org.pcmm.gates.impl.IPv6Classifier(srcAddress, dstAddress, srcPortBegin, dstPortBegin, priority,
463                         srcPortEnd, dstPortEnd, classifierId, ActivationState.ACTIVE, action, flowLabelFlag, tcLow,
464                         tcHigh, tcMask, flowLabelId, nextHdr, srcPrefixLen, dstPrefLen));
465     }
466 }