2 * Copyright (c) 2015 CableLabs and others. All rights reserved.
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
9 package org.opendaylight.controller.packetcable.provider;
11 import static com.google.common.base.Preconditions.checkNotNull;
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;
53 * Build PCMM gate requests from API QoS Gate objects
55 public class PCMMGateReqBuilder {
57 private final Logger logger = LoggerFactory.getLogger(PCMMGateReqBuilder.class);
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;
71 public PCMMGateReq build() {
72 return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers,
73 gateID, error, gateState, gateTimeInfo, gateUsageInfo);
76 public void setAmId(final AmId qosAmId) {
77 amid = new AMID(qosAmId.getAmType().shortValue(), qosAmId.getAmTag().shortValue());
80 public void setSubscriberId(final InetAddress qosSubId) {
81 subscriberID = new SubscriberID(qosSubId);
84 public void setGateSpec(final GateSpec qosGateSpec, final ServiceFlowDirection scnDirection) {
86 final ServiceFlowDirection qosDir;
87 if (scnDirection != null) {
88 qosDir = scnDirection;
90 if (qosGateSpec.getDirection() != null) {
91 qosDir = qosGateSpec.getDirection();
93 // TODO - determine if this is a valid default value
94 qosDir = ServiceFlowDirection.Ds;
98 final Direction gateDir;
99 if (qosDir == ServiceFlowDirection.Ds) {
100 gateDir = Direction.DOWNSTREAM;
102 gateDir = Direction.UPSTREAM;
105 // DSCP/TOS Overwrite
107 final byte gateTosMask;
109 final TosByte tosOverwrite = qosGateSpec.getDscpTosOverwrite();
110 if (tosOverwrite != null) {
112 TosByte tosMask = qosGateSpec.getDscpTosMask();
113 if (tosMask != null) {
114 gateTosMask = tosMask.getValue().byteValue();
116 gateTosMask = (byte) 0xff;
119 // TODO - These values appear to be required
123 gateSpec = new org.pcmm.gates.impl.GateSpec(gateDir, dscptos, gateTosMask);
126 public void setTrafficProfile(final TrafficProfile qosTrafficProfile) {
127 if (qosTrafficProfile.getServiceClassName() != null) {
129 new DOCSISServiceClassNameTrafficProfile(qosTrafficProfile.getServiceClassName().getValue());
133 private InetAddress getByName(final String ipAddressStr) {
135 return InetAddress.getByName(ipAddressStr);
136 } catch (UnknownHostException e) {
137 logger.error(e.getMessage());
142 public void setClassifiers(final List<ClassifierContainer> classifiers) {
143 checkNotNull(classifiers);
145 for (ClassifierContainer container : classifiers) {
146 final ClassifierChoice choice = container.getClassifierChoice();
147 final Short index = container.getClassifierId();
149 if (choice instanceof QosClassifierChoice) {
150 addClassifier(index, ((QosClassifierChoice) choice).getClassifier());
152 else if (choice instanceof ExtClassifierChoice) {
153 addExtClassifier(index, ((ExtClassifierChoice) choice).getExtClassifier());
155 else if (choice instanceof Ipv6ClassifierChoice) {
156 addIpv6Classifier(index, ((Ipv6ClassifierChoice) choice).getIpv6Classifier());
159 throw new IllegalStateException("Unknown ClassifierChoice: " + choice);
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;
174 // Protocol -- zero is match any
175 if (qosClassifier.getProtocol() != null) {
176 protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
178 protocol = Protocol.NONE;
181 // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything)
183 Inet4Address srcAddress = (Inet4Address) getByName("0.0.0.0");
185 if (qosClassifier.getSrcIp() != null) {
186 srcAddress = (Inet4Address) getByName(qosClassifier.getSrcIp().getValue());
189 Inet4Address dstAddress = (Inet4Address) getByName("0.0.0.0");
191 if (qosClassifier.getDstIp() != null) {
192 dstAddress = (Inet4Address) getByName(qosClassifier.getDstIp().getValue());
196 if (qosClassifier.getSrcPort() != null) {
197 srcPort = qosClassifier.getSrcPort().getValue().shortValue();
199 if (qosClassifier.getDstPort() != null) {
200 dstPort = qosClassifier.getDstPort().getValue().shortValue();
202 if (qosClassifier.getTosByte() != null) {
203 tosOverwrite = qosClassifier.getTosByte().getValue().byteValue();
204 if (qosClassifier.getTosMask() != null) {
205 tosMask = qosClassifier.getTosMask().getValue().byteValue();
207 // set default TOS mask
208 tosMask = (byte) 0xff;
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
216 if (qosClassifier.getPriority() != null) {
217 short result = qosClassifier.getPriority();
218 priority = (byte)(result % 255);
221 // push the classifier to the gate request
222 classifiers.add(new org.pcmm.gates.impl.Classifier(protocol, tosOverwrite, tosMask, srcAddress, dstAddress, srcPort,
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());
234 protocol = Protocol.NONE;
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();
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;
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();
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;
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();
282 // set default TOS mask
283 tosMask = (byte) 0xff;
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");
290 if (qosExtClassifier.getSrcIp() != null) {
291 srcIpAddr = getInet4Address(qosExtClassifier.getSrcIp());
294 Inet4Address dstIpAddr = (Inet4Address) getByName("0.0.0.0");
295 if (qosExtClassifier.getDstIp() != null) {
296 dstIpAddr = getInet4Address(qosExtClassifier.getDstIp());
300 Inet4Address srcIpMask = (Inet4Address) getByName("255.255.255.255");
301 if (qosExtClassifier.getSrcIpMask() != null) {
302 srcIpMask = getInet4Address(qosExtClassifier.getSrcIpMask());
305 Inet4Address dstIpMask = (Inet4Address) getByName("255.255.255.255");
306 if (qosExtClassifier.getDstIpMask() != null) {
307 dstIpMask = getInet4Address(qosExtClassifier.getDstIpMask());
310 // TODO - find out what the classifier ID should really be. It was never getting set previously
311 final short classifierId = (short)index;
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;
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
321 if (qosExtClassifier.getPriority() != null) {
322 short result = qosExtClassifier.getPriority();
323 priority = (byte)(result % 255);
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,
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;
344 private void addIpv6Classifier(final Short index, final Ipv6Classifier qosIpv6Classifier) {
347 if (qosIpv6Classifier.getNextHdr() != null) {
348 nextHdr = qosIpv6Classifier.getNextHdr().getValue().shortValue();
350 // default: match any nextHdr is 256 because nextHdr 0 is Hop-by-Hop option
352 nextHdr = (short) 256;
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");
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]);
367 srcPrefixLen = (byte) 128;
372 // TODO - try to make these two variables immutable
373 Inet6Address dstAddress = (Inet6Address) getByName("0::0");
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;
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();
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;
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();
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;
420 if (qosIpv6Classifier.getTcLow() != null)
421 tcLow = qosIpv6Classifier.getTcLow().getValue().byteValue();
422 else tcLow = (byte) 0x00;
425 if (qosIpv6Classifier.getTcHigh() != null)
426 tcHigh = qosIpv6Classifier.getTcHigh().getValue().byteValue();
427 else tcHigh = (byte) 0x00;
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;
435 FlowLabel flowLabelFlag = FlowLabel.IRRELEVANT;
438 if (qosIpv6Classifier.getFlowLabel() != null) {
439 flowLabelFlag = FlowLabel.VALID;
440 flowLabelId = qosIpv6Classifier.getFlowLabel().intValue();
444 // TODO - find out what the classifier ID should really be. It was never getting set previously
445 final short classifierId = (short)index;
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;
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
455 if (qosIpv6Classifier.getPriority() != null) {
456 short result = qosIpv6Classifier.getPriority();
457 priority = (byte)(result % 255);
460 // push the IPv6 classifier to the gate request
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));