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.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;
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;
171 byte priority = (byte) 64;
172 //byte priority = index.byteValue();
176 // Protocol -- zero is match any
177 if (qosClassifier.getProtocol() != null) {
178 protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
180 protocol = Protocol.NONE;
183 // IP Addresss and mask wildcards - addr byte 0 for no match (or match anything)
185 Inet4Address srcAddress = (Inet4Address) getByName("0.0.0.0");
187 if (qosClassifier.getSrcIp() != null) {
188 srcAddress = (Inet4Address) getByName(qosClassifier.getSrcIp().getValue());
191 Inet4Address dstAddress = (Inet4Address) getByName("0.0.0.0");
193 if (qosClassifier.getDstIp() != null) {
194 dstAddress = (Inet4Address) getByName(qosClassifier.getDstIp().getValue());
198 if (qosClassifier.getSrcPort() != null) {
199 srcPort = qosClassifier.getSrcPort().getValue().shortValue();
201 if (qosClassifier.getDstPort() != null) {
202 dstPort = qosClassifier.getDstPort().getValue().shortValue();
204 if (qosClassifier.getTosByte() != null) {
205 tosOverwrite = qosClassifier.getTosByte().getValue().byteValue();
206 if (qosClassifier.getTosMask() != null) {
207 tosMask = qosClassifier.getTosMask().getValue().byteValue();
209 // set default TOS mask
210 tosMask = (byte) 0xff;
213 // push the classifier to the gate request
214 classifiers.add(new org.pcmm.gates.impl.Classifier(protocol, tosOverwrite, tosMask, srcAddress, dstAddress, srcPort,
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());
227 protocol = Protocol.NONE;
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();
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;
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();
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;
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();
275 // set default TOS mask
276 tosMask = (byte) 0xff;
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");
283 if (qosExtClassifier.getSrcIp() != null) {
284 srcIpAddr = getInet4Address(qosExtClassifier.getSrcIp());
287 Inet4Address dstIpAddr = (Inet4Address) getByName("0.0.0.0");
288 if (qosExtClassifier.getDstIp() != null) {
289 dstIpAddr = getInet4Address(qosExtClassifier.getDstIp());
293 Inet4Address srcIpMask = (Inet4Address) getByName("255.255.255.255");
294 if (qosExtClassifier.getSrcIpMask() != null) {
295 srcIpMask = getInet4Address(qosExtClassifier.getSrcIpMask());
298 Inet4Address dstIpMask = (Inet4Address) getByName("255.255.255.255");
299 if (qosExtClassifier.getDstIpMask() != null) {
300 dstIpMask = getInet4Address(qosExtClassifier.getDstIpMask());
303 // TODO - find out what the classifier ID should really be. It was never getting set previously
304 final short classifierId = (short)index;
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;
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,
316 private Inet4Address getInet4Address(
317 final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address address) {
318 if (address != null) {
319 final InetAddress out = getByName(address.getValue());
320 if (out != null && out instanceof Inet4Address) {
321 return (Inet4Address) out;
327 private void addIpv6Classifier(final Short index, final Ipv6Classifier qosIpv6Classifier) {
330 if (qosIpv6Classifier.getNextHdr() != null) {
331 nextHdr = qosIpv6Classifier.getNextHdr().getValue().shortValue();
333 // default: match any nextHdr is 256 because nextHdr 0 is Hop-by-Hop option
335 nextHdr = (short) 256;
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");
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]);
350 srcPrefixLen = (byte) 128;
355 // TODO - try to make these two variables immutable
356 Inet6Address dstAddress = (Inet6Address) getByName("0::0");
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;
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();
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;
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();
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;
403 if (qosIpv6Classifier.getTcLow() != null)
404 tcLow = qosIpv6Classifier.getTcLow().getValue().byteValue();
405 else tcLow = (byte) 0x00;
408 if (qosIpv6Classifier.getTcHigh() != null)
409 tcHigh = qosIpv6Classifier.getTcHigh().getValue().byteValue();
410 else tcHigh = (byte) 0x00;
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;
418 FlowLabel flowLabelFlag = FlowLabel.IRRELEVANT;
421 if (qosIpv6Classifier.getFlowLabel() != null) {
422 flowLabelFlag = FlowLabel.VALID;
423 flowLabelId = qosIpv6Classifier.getFlowLabel().intValue();
427 // TODO - find out what the classifier ID should really be. It was never getting set previously
428 final short classifierId = (short)index;
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;
433 // push the IPv6 classifier to the gate request
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));