Upgrade ietf-{inet,yang}-types to 2013-07-15
[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.rev151101.ServiceFlowDirection;
20 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.TosByte;
21 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.attributes.AmId;
22 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.classifier.attributes.classifiers.ClassifierContainer;
23 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.classifier.attributes.classifiers.classifier.container.ClassifierChoice;
24 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.classifier.attributes.classifiers.classifier.container.classifier.choice.ExtClassifierChoice;
25 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.classifier.attributes.classifiers.classifier.container.classifier.choice.Ipv6ClassifierChoice;
26 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.classifier.attributes.classifiers.classifier.container.classifier.choice.QosClassifierChoice;
27 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.classifier.Classifier;
28 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.ext.classifier.ExtClassifier;
29 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gate.spec.GateSpec;
30 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.ipv6.classifier.Ipv6Classifier;
31 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.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 = index.byteValue();
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) 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) 64,
436                         srcPortEnd, dstPortEnd, classifierId, ActivationState.ACTIVE, action, flowLabelFlag, tcLow,
437                         tcHigh, tcMask, flowLabelId, nextHdr, srcPrefixLen, dstPrefLen));
438     }
439 }