Added GateInfo to Op Ds and RPCs to support gate update requests
[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         Inet4Address srcAddress = null;
170         Inet4Address dstAddress = null;
171         short srcPort = (short) 0;
172         short dstPort = (short) 0;
173         byte priority = (byte) 64;
174         //byte priority = index.byteValue();
175         
176         
177         // Legacy classifier
178         if (qosClassifier.getProtocol() != null) {
179             protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
180         }
181         if (qosClassifier.getSrcIp() != null) {
182             final InetAddress sip = getByName(qosClassifier.getSrcIp().getValue());
183             if (sip != null && sip instanceof Inet4Address) {
184                 srcAddress = (Inet4Address) sip;
185             }
186         }
187         if (qosClassifier.getDstIp() != null) {
188             final InetAddress dip = getByName(qosClassifier.getDstIp().getValue());
189             if (dip != null && dip instanceof Inet4Address) {
190                 dstAddress = (Inet4Address) dip;
191             }
192         }
193         if (qosClassifier.getSrcPort() != null) {
194             srcPort = qosClassifier.getSrcPort().getValue().shortValue();
195         }
196         if (qosClassifier.getDstPort() != null) {
197             dstPort = qosClassifier.getDstPort().getValue().shortValue();
198         }
199         if (qosClassifier.getTosByte() != null) {
200             tosOverwrite = qosClassifier.getTosByte().getValue().byteValue();
201             if (qosClassifier.getTosMask() != null) {
202                 tosMask = qosClassifier.getTosMask().getValue().byteValue();
203             } else {
204                 // set default TOS mask
205                 tosMask = (byte) 0xff;
206             }
207         }
208         // push the classifier to the gate request
209         classifiers.add(new org.pcmm.gates.impl.Classifier(protocol, tosOverwrite, tosMask, srcAddress, dstAddress, srcPort,
210                         dstPort, priority));
211     }
212
213     private void addExtClassifier(final Short index, final ExtClassifier qosExtClassifier) {
214         // Extended classifier
215         final byte priority = (byte) 64;
216         final ActivationState activationState = ActivationState.ACTIVE;
217         // Protocol -- zero is match any
218         final Protocol protocol;
219         if (qosExtClassifier.getProtocol() != null) {
220             protocol = Protocol.valueOf(qosExtClassifier.getProtocol().getValue().shortValue());
221         } else {
222             protocol = Protocol.NONE;
223         }
224
225         // default source port range must be set to match any even if qosExtClassifier has no range
226         // match any port range is 0-65535, NOT 0-0
227         // TODO - try to make these two variables immutable
228         short srcStartPort = (short) 0;
229         short srcEndPort = (short) 65535;
230         if (qosExtClassifier.getSrcPortStart() != null) {
231             srcStartPort = qosExtClassifier.getSrcPortStart().getValue().shortValue();
232             srcEndPort = srcStartPort;
233             if (qosExtClassifier.getSrcPortEnd() != null) {
234                 srcEndPort = qosExtClassifier.getSrcPortEnd().getValue().shortValue();
235             }
236             if (srcStartPort > srcEndPort) {
237                 logger.warn("Start port %d > End port %d in ext-classifier source port range -- forcing to same",
238                         srcStartPort, srcEndPort);
239                 srcEndPort = srcStartPort;
240             }
241         }
242         // default destination port range must be set to match any even if qosExtClassifier has no range
243         // match any port range is 0-65535, NOT 0-0
244         // TODO - try to make these two variables immutable
245         short dstStartPort = (short) 0;
246         short dstEndPort = (short) 65535;
247         if (qosExtClassifier.getDstPortStart() != null) {
248             dstStartPort = qosExtClassifier.getDstPortStart().getValue().shortValue();
249             dstEndPort = dstStartPort;
250             if (qosExtClassifier.getDstPortEnd() != null) {
251                 dstEndPort = qosExtClassifier.getDstPortEnd().getValue().shortValue();
252             }
253             if (dstStartPort > dstEndPort) {
254                 logger.warn("Start port %d > End port %d in ext-classifier destination port range -- forcing to same",
255                         dstStartPort, dstEndPort);
256                 dstEndPort = dstStartPort;
257             }
258         }
259
260         // DSCP/TOP byte
261         // TODO - try to make these two variables immutable
262         byte tosOverwrite = 0;
263         byte tosMask = (byte)0x00;
264         if (qosExtClassifier.getTosByte() != null) {
265             // OR in the DSCP/TOS enable bit 0x01
266             tosOverwrite = (byte) (qosExtClassifier.getTosByte().getValue().byteValue() | 0x01);
267             if (qosExtClassifier.getTosMask() != null) {
268                 tosMask = qosExtClassifier.getTosMask().getValue().byteValue();
269             } else {
270                 // set default TOS mask
271                 tosMask = (byte) 0xff;
272             }
273         }
274
275         // TODO - find out what the classifier ID should really be. It was never getting set previously
276         final short classifierId = (short)index;
277
278         // TODO - find out what the action value should really be. It was never getting set previously
279         final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
280
281         // push the extended classifier to the gate request
282         classifiers.add(new org.pcmm.gates.impl.ExtendedClassifier(protocol, tosOverwrite, tosMask,
283                 getInet4Address(qosExtClassifier.getSrcIp()), getInet4Address(qosExtClassifier.getDstIp()),
284                 srcStartPort, dstStartPort, priority, getInet4Address(qosExtClassifier.getSrcIpMask()),
285                 getInet4Address(qosExtClassifier.getDstIpMask()), srcEndPort, dstEndPort, classifierId, activationState,
286                 action));
287     }
288
289     private Inet4Address getInet4Address(
290             final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address address) {
291         if (address != null) {
292             final InetAddress out = getByName(address.getValue());
293             if (out != null && out instanceof Inet4Address) {
294                 return (Inet4Address) out;
295             }
296         }
297         return null;
298     }
299
300     private void addIpv6Classifier(final Short index, final Ipv6Classifier qosIpv6Classifier) {
301         // Next Header
302         final short nextHdr;
303         if (qosIpv6Classifier.getNextHdr() != null) {
304             nextHdr = qosIpv6Classifier.getNextHdr().getValue().shortValue();
305         }
306         // default: match any nextHdr is 256 because nextHdr 0 is Hop-by-Hop option
307         else {
308             nextHdr = (short) 256;
309         }
310
311         // Source IPv6 address & prefix len
312         // TODO - try to make these two variables immutable
313         byte srcPrefixLen = (byte) 128;
314         Inet6Address srcAddress = null;
315         if (qosIpv6Classifier.getSrcIp6() != null) {
316             String[] parts = qosIpv6Classifier.getSrcIp6().getValue().split("/");
317             String Ipv6AddressStr = parts[0];
318             srcAddress = (Inet6Address) getByName(Ipv6AddressStr);
319             if (parts.length > 1) {
320                 srcPrefixLen = (byte) Integer.parseInt(parts[1]);
321             } else {
322                 srcPrefixLen = (byte) 128;
323             }
324
325         }
326
327         // TODO - try to make these two variables immutable
328         Inet6Address dstAddress = null;
329         byte dstPrefLen = (byte) 128;
330         // Destination IPv6 address & prefix len
331         if (qosIpv6Classifier.getDstIp6() != null) {
332             final String[] parts = qosIpv6Classifier.getDstIp6().getValue().split("/");
333             final String Ipv6AddressStr = parts[0];
334             dstAddress = (Inet6Address)getByName(Ipv6AddressStr);
335             if (parts.length > 1) dstPrefLen = (byte) Integer.parseInt(parts[1]);
336             else dstPrefLen = (byte) 128;
337         }
338
339         // default source port range must be set to match any -- even if qosExtClassifier has no range value
340         // match any port range is 0-65535, NOT 0-0
341         short srcPortBegin = (short) 0;
342         short srcPortEnd = (short) 65535;
343         if (qosIpv6Classifier.getSrcPortStart() != null) {
344             srcPortBegin = qosIpv6Classifier.getSrcPortStart().getValue().shortValue();
345             srcPortEnd = srcPortBegin;
346             if (qosIpv6Classifier.getSrcPortEnd() != null) {
347                 srcPortEnd = qosIpv6Classifier.getSrcPortEnd().getValue().shortValue();
348             }
349             if (srcPortBegin > srcPortEnd) {
350                 logger.warn("Start port %d > End port %d in ipv6-classifier source port range -- forcing to same",
351                         srcPortBegin, srcPortEnd);
352                 srcPortEnd = srcPortBegin;
353             }
354         }
355
356         // default destination port range must be set to match any -- even if qosExtClassifier has no range value
357         // match any port range is 0-65535, NOT 0-0
358         short dstPortBegin = (short) 0;
359         short dstPortEnd = (short) 65535;
360         if (qosIpv6Classifier.getDstPortStart() != null) {
361             dstPortBegin = qosIpv6Classifier.getDstPortStart().getValue().shortValue();
362             dstPortEnd = dstPortBegin;
363             if (qosIpv6Classifier.getDstPortEnd() != null) {
364                 dstPortEnd = qosIpv6Classifier.getDstPortEnd().getValue().shortValue();
365             }
366             if (dstPortBegin > dstPortEnd) {
367                 logger.warn("Start port %d > End port %d in ipv6-classifier destination port range -- forcing to same",
368                         dstPortBegin, dstPortEnd);
369                 dstPortEnd = dstPortBegin;
370             }
371         }
372
373         final byte tcLow;
374         if (qosIpv6Classifier.getTcLow() != null)
375             tcLow = qosIpv6Classifier.getTcLow().getValue().byteValue();
376         else tcLow = (byte) 0x00;
377
378         final byte tcHigh;
379         if (qosIpv6Classifier.getTcHigh() != null)
380             tcHigh = qosIpv6Classifier.getTcHigh().getValue().byteValue();
381         else tcHigh = (byte) 0x00;
382
383         final byte tcMask;
384         if (qosIpv6Classifier.getTcHigh() != null)
385             tcMask = qosIpv6Classifier.getTcHigh().getValue().byteValue();
386         else if (qosIpv6Classifier.getTcLow() != null) tcMask = (byte) 0xff;
387         else tcMask = (byte) 0x00;
388
389         // TODO - find out what the classifier ID should really be. It was never getting set previously
390         final short classifierId = (short)index;
391
392         // TODO - find out what the action value should really be. It was never getting set previously
393         final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
394
395         // push the IPv6 classifier to the gate request
396         classifiers.add(
397                 new org.pcmm.gates.impl.IPv6Classifier(srcAddress, dstAddress, srcPortBegin, dstPortBegin, (byte) 64,
398                         srcPortEnd, dstPortEnd, classifierId, ActivationState.ACTIVE, action, FlowLabel.VALID, tcLow,
399                         tcHigh, tcMask, qosIpv6Classifier.getFlowLabel().intValue(), nextHdr, srcPrefixLen, dstPrefLen));
400     }
401 }