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.rev170224.ServiceFlowDirection;
20 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.TosByte;
21 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.attributes.AmId;
22 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.classifier.attributes.classifiers.ClassifierContainer;
23 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.classifier.attributes.classifiers.classifier.container.ClassifierChoice;
24 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.classifier.attributes.classifiers.classifier.container.classifier.choice.ExtClassifierChoice;
25 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.classifier.attributes.classifiers.classifier.container.classifier.choice.Ipv6ClassifierChoice;
26 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.classifier.attributes.classifiers.classifier.container.classifier.choice.QosClassifierChoice;
27 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.classifier.Classifier;
28 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.ext.classifier.ExtClassifier;
29 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gate.spec.GateSpec;
30 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.ipv6.classifier.Ipv6Classifier;
31 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.TrafficProfile;
32 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.serviceclass.name.profile.ServiceClassNameProfile;
33 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.flow.spec.profile.FlowSpecProfile;
34 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.ugs.profile.UgsProfile;
35 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.rtp.profile.RtpProfile;
36 import org.pcmm.gates.IClassifier;
37 import org.pcmm.gates.IClassifier.Protocol;
38 import org.pcmm.gates.IExtendedClassifier;
39 import org.pcmm.gates.IExtendedClassifier.ActivationState;
40 import org.pcmm.gates.IGateSpec.Direction;
41 import org.pcmm.gates.IIPv6Classifier.FlowLabel;
42 import org.pcmm.gates.ITrafficProfile;
43 import org.pcmm.gates.impl.AMID;
44 import org.pcmm.gates.impl.DOCSISServiceClassNameTrafficProfile;
45 import org.pcmm.gates.impl.DOCSISFlowSpecTrafficProfile;
46 import org.pcmm.gates.impl.DOCSISUGSTrafficProfile;
47 import org.pcmm.gates.impl.DOCSISRTPTrafficProfile;
48 import org.pcmm.gates.impl.GateID;
49 import org.pcmm.gates.impl.GateState;
50 import org.pcmm.gates.impl.GateTimeInfo;
51 import org.pcmm.gates.impl.GateUsageInfo;
52 import org.pcmm.gates.impl.PCMMError;
53 import org.pcmm.gates.impl.PCMMGateReq;
54 import org.pcmm.gates.impl.SessionClassID;
55 import org.pcmm.gates.impl.SubscriberID;
56 import org.pcmm.gates.impl.TransactionID;
57 import org.pcmm.utils.PCMMUtils;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.TrafficProfile;
61 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.traffic.profile.TrafficProfileChoice;
62 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.traffic.profile.traffic.profile.choice.FlowSpecChoice;
63 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.traffic.profile.traffic.profile.choice.ServiceClassNameChoice;
64 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.traffic.profile.traffic.profile.choice.RtpChoice;
65 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.traffic.profile.traffic.profile.choice.UgsChoice;
68 * Build PCMM gate requests from API QoS Gate objects
70 public class PCMMGateReqBuilder {
72 private final Logger logger = LoggerFactory.getLogger(PCMMGateReqBuilder.class);
74 private GateID gateID = null;
75 private AMID amid = null;
76 private SubscriberID subscriberID = null;
77 private TransactionID transactionID = null;
78 private org.pcmm.gates.impl.GateSpec gateSpec = null;
79 private ITrafficProfile trafficProfile = null;
80 private final List<IClassifier> classifiers = Lists.newArrayListWithExpectedSize(4);
81 private PCMMError error = null;
82 private GateState gateState = null;
83 private GateTimeInfo gateTimeInfo = null;
84 private GateUsageInfo gateUsageInfo = null;
86 public PCMMGateReq build() {
87 return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers,
88 gateID, error, gateState, gateTimeInfo, gateUsageInfo);
91 public void setAmId(final AmId qosAmId) {
92 amid = new AMID(qosAmId.getAmType().shortValue(), qosAmId.getAmTag().shortValue());
95 public void setSubscriberId(final InetAddress qosSubId) {
96 subscriberID = new SubscriberID(qosSubId);
99 public void setGateId(int gateId) {
100 gateID = new GateID(gateId);
103 public void setGateSpec(final GateSpec qosGateSpec) {
105 final ServiceFlowDirection qosDir = qosGateSpec.getDirection();
107 // convert to PCMM API Type
108 final Direction gateDir;
109 if (qosDir == ServiceFlowDirection.Ds) {
110 gateDir = Direction.DOWNSTREAM;
112 gateDir = Direction.UPSTREAM;
115 final byte dscptos = 1;
116 final byte gateTosMask;
118 TosByte tosMask = qosGateSpec.getDscpTosMask();
119 if (tosMask != null) {
120 gateTosMask = tosMask.getValue().byteValue();
122 gateTosMask = (byte) 0xff;
125 java.lang.Short scid = qosGateSpec.getSessionClassId();
128 bscid = (byte)(qosGateSpec.getSessionClassId() & 0x00ff);
131 java.lang.Long inactivity = qosGateSpec.getInactivityTimer();
132 short sinactivity = 300;
133 if (inactivity != null) {
134 sinactivity = inactivity.shortValue();
137 gateSpec = new org.pcmm.gates.impl.GateSpec(gateDir, dscptos, gateTosMask,
138 new SessionClassID(bscid),
139 (short)1,(short)300,sinactivity,(short)0);
142 public void setTrafficProfile(final TrafficProfile qosTrafficProfile) {
143 TrafficProfileChoice choice = qosTrafficProfile.getTrafficProfileChoice();
145 if (choice instanceof ServiceClassNameChoice) {
146 ServiceClassNameProfile scnp = ((ServiceClassNameChoice)choice).getServiceClassNameProfile();
147 trafficProfile = new DOCSISServiceClassNameTrafficProfile(scnp.getServiceClassName().getValue());
149 else if (choice instanceof FlowSpecChoice) {
150 FlowSpecProfile fsp = ((FlowSpecChoice)choice).getFlowSpecProfile();
151 trafficProfile = new DOCSISFlowSpecTrafficProfile(fsp.getTokenBucketRate(),
152 fsp.getTokenBucketSize(),
153 fsp.getPeakDataRate(),
154 fsp.getMinimumPolicedUnit(),
155 fsp.getMaximumPacketSize(),
159 else if (choice instanceof UgsChoice) {
160 UgsProfile ugsp = ((UgsChoice)choice).getUgsProfile();
161 trafficProfile = new DOCSISUGSTrafficProfile(ugsp.getRequestTransmissionPolicy(),
162 ugsp.getUnsolicitedGrantSize(),
163 ugsp.getGrantsPerInterval(),
164 ugsp.getNominalGrantInterval(),
165 ugsp.getToleratedGrantJitter(),
166 ugsp.getUpstreamPeakTrafficRate(),
167 ugsp.getRequiredAttributeMask(),
168 ugsp.getForbiddenAttributeMask(),
169 ugsp.getAttributeAggregationRuleMask());
171 else if (choice instanceof RtpChoice) {
172 RtpProfile rtpp = ((RtpChoice)choice).getRtpProfile();
173 trafficProfile = new DOCSISRTPTrafficProfile(rtpp.getRequestTransmissionPolicy(),
174 rtpp.getMaximumSustainedTrafficRate(),
175 rtpp.getMaximumTrafficBurst(),
176 rtpp.getMinimumReservedTrafficRate(),
177 rtpp.getAmrtrPacketSize().longValue(),
178 rtpp.getMaximumConcatenatedBurst().longValue(),
179 rtpp.getNominalPollingInterval(),
180 rtpp.getToleratedPollJitter(),
181 rtpp.getUpstreamPeakTrafficRate(),
182 rtpp.getRequiredAttributeMask(),
183 rtpp.getForbiddenAttributeMask(),
184 rtpp.getAttributeAggregationRuleMask());
187 logger.debug("PCMMGateReq().setTrafficProfile() Unsupported Traffic Profile: " + choice.getClass().getName());
191 private InetAddress getByName(final String ipAddressStr) {
193 return InetAddress.getByName(ipAddressStr);
194 } catch (UnknownHostException e) {
195 logger.error(e.getMessage());
200 public void setClassifiers(final List<ClassifierContainer> classifiers) {
201 checkNotNull(classifiers);
203 for (ClassifierContainer container : classifiers) {
204 final ClassifierChoice choice = container.getClassifierChoice();
205 final Short index = container.getClassifierId();
207 if (choice instanceof QosClassifierChoice) {
208 addClassifier(index, ((QosClassifierChoice) choice).getClassifier());
210 else if (choice instanceof ExtClassifierChoice) {
211 addExtClassifier(index, ((ExtClassifierChoice) choice).getExtClassifier());
213 else if (choice instanceof Ipv6ClassifierChoice) {
214 addIpv6Classifier(index, ((Ipv6ClassifierChoice) choice).getIpv6Classifier());
217 throw new IllegalStateException("Unknown ClassifierChoice: " + choice);
222 private void addClassifier(final Short index,final Classifier qosClassifier) {
223 // TODO - try and make these variables immutable
224 Protocol protocol = null;
225 byte tosOverwrite = 0;
226 byte tosMask = (byte)0x0;
227 short srcPort = (short) 0;
228 short dstPort = (short) 0;
232 // Protocol -- zero is match any
233 if (qosClassifier.getProtocol() != null) {
234 protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
236 protocol = Protocol.NONE;
239 // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything)
241 Inet4Address srcAddress = (Inet4Address) getByName("0.0.0.0");
243 if (qosClassifier.getSrcIp() != null) {
244 srcAddress = (Inet4Address) getByName(qosClassifier.getSrcIp().getValue());
247 Inet4Address dstAddress = (Inet4Address) getByName("0.0.0.0");
249 if (qosClassifier.getDstIp() != null) {
250 dstAddress = (Inet4Address) getByName(qosClassifier.getDstIp().getValue());
254 if (qosClassifier.getSrcPort() != null) {
255 srcPort = qosClassifier.getSrcPort().getValue().shortValue();
257 if (qosClassifier.getDstPort() != null) {
258 dstPort = qosClassifier.getDstPort().getValue().shortValue();
260 if (qosClassifier.getTosByte() != null) {
261 tosOverwrite = qosClassifier.getTosByte().getValue().byteValue();
262 if (qosClassifier.getTosMask() != null) {
263 tosMask = qosClassifier.getTosMask().getValue().byteValue();
265 // set default TOS mask
266 tosMask = (byte) 0xff;
270 // The packetcable.yang models priority as an uint8 which means the java generated
271 // implementation saves the value in a short, so we mask it back into a byte
274 if (qosClassifier.getPriority() != null) {
275 short result = qosClassifier.getPriority();
276 priority = (byte)(result % 255);
279 // push the classifier to the gate request
280 classifiers.add(new org.pcmm.gates.impl.Classifier(protocol, tosOverwrite, tosMask, srcAddress, dstAddress, srcPort,
284 private void addExtClassifier(final Short index, final ExtClassifier qosExtClassifier) {
285 // Extended classifier
286 // Protocol -- zero is match any
287 final Protocol protocol;
288 if (qosExtClassifier.getProtocol() != null) {
289 protocol = Protocol.valueOf(qosExtClassifier.getProtocol().getValue().shortValue());
291 protocol = Protocol.NONE;
294 // default source port range must be set to match any even if qosExtClassifier has no range
295 // match any port range is 0-65535, NOT 0-0
296 // TODO - try to make these two variables immutable
297 short srcStartPort = (short) 0;
298 short srcEndPort = (short) 65535;
299 if (qosExtClassifier.getSrcPortStart() != null) {
300 srcStartPort = qosExtClassifier.getSrcPortStart().getValue().shortValue();
301 srcEndPort = srcStartPort;
302 if (qosExtClassifier.getSrcPortEnd() != null) {
303 srcEndPort = qosExtClassifier.getSrcPortEnd().getValue().shortValue();
305 if ((int)(srcStartPort & 0xffff) > (int) (srcEndPort & 0xffff)) {
306 logger.warn("Start port %d > End port %d in ext-classifier source port range -- forcing to same",
307 srcStartPort, srcEndPort);
308 srcEndPort = srcStartPort;
311 // default destination port range must be set to match any even if qosExtClassifier has no range
312 // match any port range is 0-65535, NOT 0-0
313 // TODO - try to make these two variables immutable
314 short dstStartPort = (short) 0;
315 short dstEndPort = (short) 65535;
316 if (qosExtClassifier.getDstPortStart() != null) {
317 dstStartPort = qosExtClassifier.getDstPortStart().getValue().shortValue();
318 dstEndPort = dstStartPort;
319 if (qosExtClassifier.getDstPortEnd() != null) {
320 dstEndPort = qosExtClassifier.getDstPortEnd().getValue().shortValue();
322 if ((int)(dstStartPort & 0xffff) > (int)(dstEndPort & 0xffff)) {
323 logger.warn("Start port %d > End port %d in ext-classifier destination port range -- forcing to same",
324 dstStartPort, dstEndPort);
325 dstEndPort = dstStartPort;
330 // TODO - try to make these two variables immutable
331 byte tosOverwrite = 0;
332 byte tosMask = (byte)0x00;
333 if (qosExtClassifier.getTosByte() != null) {
334 // OR in the DSCP/TOS enable bit 0x01
335 tosOverwrite = (byte) (qosExtClassifier.getTosByte().getValue().byteValue() | 0x01);
336 if (qosExtClassifier.getTosMask() != null) {
337 tosMask = qosExtClassifier.getTosMask().getValue().byteValue();
339 // set default TOS mask
340 tosMask = (byte) 0xff;
344 // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything) and mask is 255.255.255.255 by default
345 Inet4Address srcIpAddr = (Inet4Address) getByName("0.0.0.0");
347 if (qosExtClassifier.getSrcIp() != null) {
348 srcIpAddr = getInet4Address(qosExtClassifier.getSrcIp());
351 Inet4Address dstIpAddr = (Inet4Address) getByName("0.0.0.0");
352 if (qosExtClassifier.getDstIp() != null) {
353 dstIpAddr = getInet4Address(qosExtClassifier.getDstIp());
357 Inet4Address srcIpMask = (Inet4Address) getByName("255.255.255.255");
358 if (qosExtClassifier.getSrcIpMask() != null) {
359 srcIpMask = getInet4Address(qosExtClassifier.getSrcIpMask());
362 Inet4Address dstIpMask = (Inet4Address) getByName("255.255.255.255");
363 if (qosExtClassifier.getDstIpMask() != null) {
364 dstIpMask = getInet4Address(qosExtClassifier.getDstIpMask());
367 // TODO - find out what the classifier ID should really be. It was never getting set previously
368 final short classifierId = (short)index;
370 // TODO - find out what the action value should really be. It was never getting set previously
371 final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
374 // Convert from Enum to byte for serialization
376 ActivationState activationState = ActivationState.ACTIVE;
377 if (qosExtClassifier.getActivationState() != null) {
378 activationState = ActivationState.valueOf((byte)qosExtClassifier.getActivationState().getIntValue());
382 // The packetcable.yang models priority as an uint8 which means the java generated
383 // implementation saves the value in a short, so we mask it back into a byte
386 if (qosExtClassifier.getPriority() != null) {
387 short result = qosExtClassifier.getPriority();
388 priority = (byte)(result % 255);
391 // push the extended classifier to the gate request
392 classifiers.add(new org.pcmm.gates.impl.ExtendedClassifier(protocol, tosOverwrite, tosMask,
393 srcIpAddr, dstIpAddr,
394 srcStartPort, dstStartPort, priority, srcIpMask, dstIpMask, srcEndPort, dstEndPort, classifierId, activationState,
398 private Inet4Address getInet4Address(
399 final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address address) {
400 if (address != null) {
401 final InetAddress out = getByName(address.getValue());
402 if (out != null && out instanceof Inet4Address) {
403 return (Inet4Address) out;
409 private void addIpv6Classifier(final Short index, final Ipv6Classifier qosIpv6Classifier) {
412 if (qosIpv6Classifier.getNextHdr() != null) {
413 nextHdr = qosIpv6Classifier.getNextHdr().getValue().shortValue();
415 // default: match any nextHdr is 256 because nextHdr 0 is Hop-by-Hop option
417 nextHdr = (short) 256;
420 // Source IPv6 address & prefix len
421 // TODO - try to make these two variables immutable
422 byte srcPrefixLen = (byte) 128;
423 Inet6Address srcAddress = (Inet6Address) getByName("0::0");
425 if (qosIpv6Classifier.getSrcIp6() != null) {
426 String[] parts = qosIpv6Classifier.getSrcIp6().getValue().split("/");
427 String Ipv6AddressStr = parts[0];
428 srcAddress = (Inet6Address) getByName(Ipv6AddressStr);
429 if (parts.length > 1) {
430 srcPrefixLen = (byte) Integer.parseInt(parts[1]);
432 srcPrefixLen = (byte) 128;
437 // TODO - try to make these two variables immutable
438 Inet6Address dstAddress = (Inet6Address) getByName("0::0");
440 byte dstPrefLen = (byte) 128;
441 // Destination IPv6 address & prefix len
442 if (qosIpv6Classifier.getDstIp6() != null) {
443 final String[] parts = qosIpv6Classifier.getDstIp6().getValue().split("/");
444 final String Ipv6AddressStr = parts[0];
445 dstAddress = (Inet6Address)getByName(Ipv6AddressStr);
446 if (parts.length > 1) dstPrefLen = (byte) Integer.parseInt(parts[1]);
447 else dstPrefLen = (byte) 128;
450 // default source port range must be set to match any -- even if qosExtClassifier has no range value
451 // match any port range is 0-65535, NOT 0-0
452 short srcPortBegin = (short) 0;
453 short srcPortEnd = (short) 65535;
454 if (qosIpv6Classifier.getSrcPortStart() != null) {
455 srcPortBegin = qosIpv6Classifier.getSrcPortStart().getValue().shortValue();
456 srcPortEnd = srcPortBegin;
457 if (qosIpv6Classifier.getSrcPortEnd() != null) {
458 srcPortEnd = qosIpv6Classifier.getSrcPortEnd().getValue().shortValue();
460 if ((int)(srcPortBegin & 0xffff) > (int)(srcPortEnd & 0xffff)) {
461 logger.warn("Start port %d > End port %d in ipv6-classifier source port range -- forcing to same",
462 srcPortBegin, srcPortEnd);
463 srcPortEnd = srcPortBegin;
467 // default destination port range must be set to match any -- even if qosExtClassifier has no range value
468 // match any port range is 0-65535, NOT 0-0
469 short dstPortBegin = (short) 0;
470 short dstPortEnd = (short) 65535;
471 if (qosIpv6Classifier.getDstPortStart() != null) {
472 dstPortBegin = qosIpv6Classifier.getDstPortStart().getValue().shortValue();
473 dstPortEnd = dstPortBegin;
474 if (qosIpv6Classifier.getDstPortEnd() != null) {
475 dstPortEnd = qosIpv6Classifier.getDstPortEnd().getValue().shortValue();
477 if ( (int)(dstPortBegin & 0xffff) > (int)(dstPortEnd & 0xffff)) {
478 logger.warn("Start port %d > End port %d in ipv6-classifier destination port range -- forcing to same",
479 dstPortBegin, dstPortEnd);
480 dstPortEnd = dstPortBegin;
485 if (qosIpv6Classifier.getTcLow() != null)
486 tcLow = qosIpv6Classifier.getTcLow().getValue().byteValue();
487 else tcLow = (byte) 0x00;
490 if (qosIpv6Classifier.getTcHigh() != null)
491 tcHigh = qosIpv6Classifier.getTcHigh().getValue().byteValue();
492 else tcHigh = (byte) 0x00;
495 if (qosIpv6Classifier.getTcHigh() != null)
496 tcMask = qosIpv6Classifier.getTcHigh().getValue().byteValue();
497 else if (qosIpv6Classifier.getTcLow() != null) tcMask = (byte) 0xff;
498 else tcMask = (byte) 0x00;
500 FlowLabel flowLabelFlag = FlowLabel.IRRELEVANT;
503 if (qosIpv6Classifier.getFlowLabel() != null) {
504 flowLabelFlag = FlowLabel.VALID;
505 flowLabelId = qosIpv6Classifier.getFlowLabel().intValue();
509 // TODO - find out what the classifier ID should really be. It was never getting set previously
510 final short classifierId = (short)index;
512 // TODO - find out what the action value should really be. It was never getting set previously
513 final IExtendedClassifier.Action action = IExtendedClassifier.Action.ADD;
516 // Convert from Enum to byte for serialization
518 ActivationState activationState = ActivationState.ACTIVE;
519 if (qosIpv6Classifier.getActivationState() != null) {
520 activationState = ActivationState.valueOf((byte)qosIpv6Classifier.getActivationState().getIntValue());
524 // The packetcable.yang models priority as an uint8 which means the java generated
525 // implementation saves the value in a short, so we mask it back into a byte
528 if (qosIpv6Classifier.getPriority() != null) {
529 short result = qosIpv6Classifier.getPriority();
530 priority = (byte)(result % 255);
533 // push the IPv6 classifier to the gate request
535 new org.pcmm.gates.impl.IPv6Classifier(srcAddress, dstAddress, srcPortBegin, dstPortBegin, priority,
536 srcPortEnd, dstPortEnd, classifierId, activationState, action, flowLabelFlag, tcLow,
537 tcHigh, tcMask, flowLabelId, nextHdr, srcPrefixLen, dstPrefLen));