Extended driver with GateState and GateInfo types.
Added GateInfo data to operationa datastore.
Added RPC to request GateState updating.
Updated cmts emulator to respond to gate info requests
Change-Id: I35bccb12636359c3613b4b06958a348037cef93b
Signed-off-by: Ryan Vail <r.vail@cablelabs.com>
final ITransactionID trID = new TransactionID(_transactionID, GateCommandType.GATE_SET);
gate.setTransactionID(trID);
- // retain the transactionId to gate request mapping for gateID recovery after response
+ // retain the transactitrIDnumonId to gate request mapping for gateID recovery after response
// see PCMMPdpReqStateMan.processReport()
final Short trIDnum = trID.getTransactionIdentifier();
logger.info("Adding gate to cache - " + gate + " with key - " + trIDnum);
*
* @throws COPSPdpException
*/
- public void sendGateInfo() throws COPSPdpException {
+ public void sendGateInfo(final IPCMMGate gate) throws COPSPdpException {
/*
* <Gate-Info> ::= <Common Header> [<Client Handle>] [<Integrity>]
*/
- final COPSSyncStateMsg msg = new COPSSyncStateMsg(getClientType(), _handle, null);
+
+ // added
+ final ITransactionID trID = new TransactionID(_transactionID, GateCommandType.GATE_INFO);
+ gate.setTransactionID(trID);
+ // retain the transactionId to gate request mapping for gateID recovery after response
+ // see PCMMPdpReqStateMan.processReport()
+ final Short trIDnum = trID.getTransactionIdentifier();
+ logger.info("Adding gate to cache - " + gate + " with key - " + trIDnum);
+ PCMMGlobalConfig.transactionGateMap.put(trIDnum, gate);
+
+ // gateDelete only requires AMID, subscriberID, and gateID
+ // remove the gateSpec, traffic profile, and classifiers from original gate request
+ gate.setGateSpec(null);
+ gate.setTrafficProfile(null);
+ gate.setClassifiers(null);
+ // clear the error object
+ gate.setError(null);
+
+
+ // XXX - GateID
+ final byte[] data = gate.getData();
+ final Set<COPSDecision> decisionSet = new HashSet<>();
+ decisionSet.add(new COPSDecision(CType.DEF, Command.INSTALL, DecisionFlag.REQERROR));
+ final Map<COPSContext, Set<COPSDecision>> decisionMap = new HashMap<>();
+ decisionMap.put(new COPSContext(RType.CONFIG, (short)0), decisionSet);
+ final COPSClientSI clientSD = new COPSClientSI(CNum.DEC, CType.CSI, new COPSData(data, 0, data.length));
+
+ //final COPSSyncStateMsg msg = new COPSSyncStateMsg(getClientType(), _handle, null);
+ final COPSDecisionMsg decisionMsg = new COPSDecisionMsg(getClientType(), _handle, decisionMap, null, clientSD);
+
try {
- msg.writeData(_sock);
+ //msg.writeData(_sock);
+ decisionMsg.writeData(_sock);
} catch (IOException e) {
throw new COPSPdpException("Failed to send the GateInfo request", e);
}
package org.pcmm;
import org.pcmm.gates.IGateID;
+import org.pcmm.gates.IGateState;
+import org.pcmm.gates.IGateTimeInfo;
+import org.pcmm.gates.IGateUsageInfo;
import org.pcmm.gates.IPCMMError.ErrorCode;
import org.pcmm.gates.IPCMMGate;
import org.pcmm.gates.ITransactionID;
logger.info("rtypemsg success");
_status = Status.ST_REPORT;
final IGateID gateID = gateMsg.getGateID();
- logger.info("Setting gate ID on gate object - " + gateID);
+ //logger.info("Setting gate ID on gate object - " + gateID);
gate.setGateID(gateID);
+
+ //setting the Gate State, Time Info and Usage Info
+ final IGateState igateState = gateMsg.getGateState();
+ gate.setGateState(igateState);
+ final IGateTimeInfo gateTimeInfo = gateMsg.getGateTimeInfo();
+ gate.setGateTimeInfo(gateTimeInfo);
+ final IGateUsageInfo gateUsageInfo = gateMsg.getGateUsageInfo();
+ gate.setGateUsageInfo(gateUsageInfo);
+
if (_thisProcess != null)
_thisProcess.successReport(this, gateMsg);
} else {
cmdType = "GateDeleteAck";
} else if (trID.getGateCommandType().equals(GateCommandType.GATE_SET_ACK)) {
cmdType = "GateSetAck";
+ } else if (trID.getGateCommandType().equals(GateCommandType.GATE_INFO_ACK)) {
+ cmdType = "GateInfoAck";
} else cmdType = null;
// capture the gateId from the response message
final IGateID gateID = gateMsg.getGateID();
logger.info("Setting gate ID on gate object - " + gateID);
gate.setGateID(gateID);
-
+ // capture the gate state from the response message
+ final IGateState igateState = gateMsg.getGateState();
+ logger.info("Setting gate ID on gate object - " + gateID);
+ gate.setGateState(igateState);
if (gateID != null) {
int gateIdInt = gateID.getGateID();
String gateIdHex = String.format("%08x", gateIdInt);
USER_ID((byte) 20),
SHARED_RES_ID((byte) 21);
- private byte value;
+ private final byte value;
SNum(byte value) {
this.value = value;
*
* * SessionClassID
* * Direction
- * * Authorized Timer
- * * Reserved Timer
+ * * AUTHORIZED Timer
+ * * RESERVED Timer
* * Committed Timer
* * Committed Recovery Timer
* * DSCP/TOS Overwrite
* MUST reserve and activate the DOCSIS flows accordingly. For Multicast Gates the CMTS needs to only support
* flows or gates in the downstream direction.
*
- * Authorized Timer limits the amount of time the authorization must remain valid before it is reserved (see
+ * AUTHORIZED Timer limits the amount of time the authorization must remain valid before it is reserved (see
* Section 6.2).
*
- * Reserved Timer limits the amount of time the reservation must remain valid before the resources are committed (see
+ * RESERVED Timer limits the amount of time the reservation must remain valid before the resources are committed (see
* Section 6.2).
*
* Committed Timer limits the amount of time a committed service flow may remain idle.
Direction getDirection();
/**
- * Authorized Timer limits the amount of time the authorization must remain
+ * AUTHORIZED Timer limits the amount of time the authorization must remain
* valid before it is reserved
*
* @return time in ms;
short getTimerT1();
/**
- * Reserved Timer limits the amount of time the reservation must remain
+ * RESERVED Timer limits the amount of time the reservation must remain
* valid before the resources are committed
*
* @return time in ms;
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates;
+
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Converter;
+import org.pcmm.base.IPCMMBaseObject;
+
+/**
+ * From the Packetcable Multimedia specification section 6.4.2.15
+ * <p>
+ * The information in the Gate State object reflects the current state of the Gate. The CMTS MUST include the Gate
+ * State object in any unsolicited messages that it sends to the Policy Server. The Policy Server may use this
+ * information to report state to the Application Manager, or for enforcing complex rules that might require state
+ * knowledge of the Gate.
+ */
+public interface IGateState extends IPCMMBaseObject {
+
+ static final Converter<String, String> converter = CaseFormat.UPPER_UNDERSCORE.converterTo(CaseFormat.UPPER_CAMEL);
+ /**
+ * The S-Type for Gate State
+ */
+ byte STYPE = 1;
+
+ /**
+ * Returns the gate State value
+ *
+ * @return - the State (2 bytes unsigned integer)
+ */
+ //short getGateState();
+ GateStateType getGateState();
+
+ GateStateReasonType getGateStateReason();
+
+ /**
+ * Gate State Types types
+ */
+ enum GateStateType {
+
+ IDLE_CLOSED((short) 1),
+ AUTHORIZED((short) 2),
+ RESERVED((short) 3),
+ COMMITTED((short) 4),
+ COMMITTED_RECOVERY((short) 5);
+
+ GateStateType(short value) {
+ this.value = value;
+ this.displayName = converter.convert(name());
+ }
+
+ public short getValue() {
+ return value;
+ }
+
+ public static GateStateType valueOf(short v) {
+ switch (v) {
+ case 1:
+ return GateStateType.IDLE_CLOSED;
+ case 2:
+ return GateStateType.AUTHORIZED;
+ case 3:
+ return GateStateType.RESERVED;
+ case 4:
+ return GateStateType.COMMITTED;
+ case 5:
+ return GateStateType.COMMITTED_RECOVERY;
+ default:
+ throw new IllegalArgumentException("not supported value");
+ }
+ }
+
+ private final short value;
+ private final String displayName;
+
+ public String toString() {
+ return displayName + "(" + getValue() + ")";
+ }
+ }
+
+
+ /**
+ * From PCMM Spec section 6.4.2.15
+ * Reason is a 2-byte unsigned integer field which MUST indicate one of the following reasons for this update:<pre>
+ * 1 = Close initiated by CMTS due to reservation reassignment
+ * 2 = Close initiated by CMTS due to lack of DOCSIS MAC-layer responses
+ * 3 = Close initiated by CMTS due to timer T1 expiration
+ * 4 = Close initiated by CMTS due to timer T2 expiration
+ * 5 = Inactivity timer expired due to Service Flow inactivity (timer T3 expiration)
+ * 6 = Close initiated by CMTS due to lack of Reservation Maintenance
+ * 7 = Gate state unchanged, but volume limit reached
+ * 8 = Close initiated by CMTS due to timer T4 expiration
+ * 9 = Gate state unchanged, but timer T2 expiration caused reservation reduction
+ * 10 = Gate state unchanged, but time limit reached
+ * 11 = Close initiated by Policy Server or CMTS, volume limit reached
+ * 12 = Close initiated by Policy Server or CMTS, time limit reached
+ * 13 = Close initiated by CMTS, other
+ * 14 = Gate state unchanged, but SharedResourceID updated
+ * 15 = Close initiated by CMTS due to loss of shared resource
+ * 65535 = Other
+ * </pre>
+ */
+ enum GateStateReasonType {
+ ZERO((short)0),
+ RESERVATION_REASSIGNMENT((short) 1),
+ LACK_OF_DOCSIS_MAC_LAYER_RESPONSES((short) 2),
+ T1_EXPIRATION((short)3),
+ T2_EXPIRATION((short)4),
+ T3_EXPIRATION((short)5),
+ LACK_OF_RESERVATION_MAINTENANCE((short)6),
+ UNCHANGED_BUT_VOLUME_LIMIT_REACHED((short)7),
+ T4_EXPIRATION((short)8),
+ UNCHANGED_BUT_T2_EXPIRATION_CAUSED_RESERVATION_REDUCTION((short)9),
+ UNCHANGED_BUT_TIME_LIMIT_REACHED((short)10),
+ VOLUME_LIMIT_REACHED((short)11),
+ TIME_LIMIT_REACHED((short)12),
+ CMTS_OTHER((short)13),
+ UNCHANGED_BUT_SHARED_RESOURCE_ID_CHANGED((short)14),
+ LOSS_OF_SHARED_RESOURCE((short)15),
+ OTHER((short) 65535);
+
+ GateStateReasonType(short value) {
+ this.value = value;
+ this.displayName = converter.convert(name());
+ }
+
+ public short getValue() {
+ return value;
+ }
+
+ public static GateStateReasonType valueOf(short v) {
+ for (GateStateReasonType type : GateStateReasonType.values()) {
+ if (type.getValue() == v) {
+ return type;
+ }
+ }
+ throw new IllegalArgumentException("not supported value: " + v);
+ }
+
+ private final short value;
+ private final String displayName;
+
+ public String toString() {
+ return displayName + "(" + getValue() + ")";
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates;
+
+import org.pcmm.base.IPCMMBaseObject;
+
+/**
+ *
+ * From the Packetcable Multimedia specification section 6.4.2.12
+ *
+ *The Gate Time Info object contains the total amount of time the Gate has been in the Committed and
+ * Committed Recovery states. This counter MUST be stopped upon the Gate transitioning out of the
+ * Committed or Committed Recovery states to either the RESERVED state or AUTHORIZED state. If the
+ * Gate subsequently transitions back to the Committed state, this counter MUST be restarted where
+ * it last stopped, i.e., when transitioning out of the Committed or Committed Recovery states.
+ */
+public interface IGateTimeInfo extends IPCMMBaseObject {
+
+ /**
+ * The S-Type for Gate Time Info
+ */
+ byte STYPE = 1;
+
+
+ /**
+ * Time Committed total amount of time the Gate has been in the Committed and Committed
+ * Recovery states
+ *
+ * @return time in seconds;
+ */
+ int getGateTimeInfo();
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates;
+
+import org.pcmm.base.IPCMMBaseObject;
+
+/**
+ *
+ * From the Packetcable Multimedia specification section 6.4.2.13
+ *
+ * The Gate Usage Info object contains a counter indicating the number of kilobytes transmitted
+ * over this Gate.
+ */
+public interface IGateUsageInfo extends IPCMMBaseObject {
+
+ /**
+ * The S-Type for Gate Time Info
+ */
+ byte STYPE = 1;
+
+
+ /**
+ * Time Committed total amount of time the Gate has been in the Committed and Committed
+ * Recovery states
+ *
+ * @return usage in kbps;
+ */
+ long getGateUsageInfo();
+}
\ No newline at end of file
/**
* Returns the error sub-code
- * @return - not null (mostly will be NA)
+ * @return - the sub error code
*/
- ErrorCode getErrorSubcode();
+ short getErrorSubcode();
/**
* Returns the error's description
*/
void setGateID(IGateID gateid);
+ /**
+ * gateState is the handle for the Gate State.
+ *
+ */
+ void setGateState(IGateState gateState);
+
/**
* (i.e., QoS limits, timers, etc.).
*
void setTransactionID(ITransactionID transactionID);
void setError(IPCMMError error);
+
+ void setGateTimeInfo(IGateTimeInfo gateTimeInfo);
+
+ void setGateUsageInfo(IGateUsageInfo gateUsageInfo);
ITransactionID getTransactionID();
*/
IGateID getGateID();
+ /**
+ * GateState is the handle for the GateState.
+ *
+ * @return gateSTATE
+ */
+ IGateState getGateState();
+
+
/**
* AMID is the handle that identifies the Application Manager and
* Application Type
*/
IPCMMError getError();
+ IGateTimeInfo getGateTimeInfo();
+
+ IGateUsageInfo getGateUsageInfo();
/**
*
public interface ITrafficProfile extends IPCMMBaseObject {
- // Authorized
+ // AUTHORIZED
byte DEFAULT_ENVELOP = 0x7;
byte getEnvelop();
return result;
}
+ @Override
+ public String toString() {
+ return "AMID{" +
+ "appType=" + appType +
+ ", appMgrTag=" + appMgrTag +
+ '}';
+ }
+
/**
* Returns an AMID object from a byte array
* @param data - the data to parse
private final int maxTrafficBurst;
/**
- * Minimum Reserved Traffic Rate is a 4-byte unsigned integer field specifying the minimum rate, in bits/sec,
+ * Minimum RESERVED Traffic Rate is a 4-byte unsigned integer field specifying the minimum rate, in bits/sec,
* reserved for this Service Flow. This field is fully defined in section C.2.2.5.4. A default Mini Rate of 0 SHOULD
- * be used if a specific Minimum Reserved Traffic Rate is not required.
+ * be used if a specific Minimum RESERVED Traffic Rate is not required.
*/
private final int minResTrafficRate;
/**
- * Assumed Minimum Reserved Traffic Rate Packet Size is a 2-byte unsigned integer field specifying an assumed
- * minimum packet size, in bytes, for which the Minimum Reserved Traffic Rate will be provided for this flow. This
- * field is fully defined in section C.2.2.5.5. A default Assumed Minimum Reserved Traffic Rate Packet Size of
- * 0 SHOULD be used if a specific Assumed Minimum Reserved Traffic Rate Packet size is not required. Upon receip
+ * Assumed Minimum RESERVED Traffic Rate Packet Size is a 2-byte unsigned integer field specifying an assumed
+ * minimum packet size, in bytes, for which the Minimum RESERVED Traffic Rate will be provided for this flow. This
+ * field is fully defined in section C.2.2.5.5. A default Assumed Minimum RESERVED Traffic Rate Packet Size of
+ * 0 SHOULD be used if a specific Assumed Minimum RESERVED Traffic Rate Packet size is not required. Upon receip
* of a value of 0 the CMTS MUST utilize its implementation-specific default size for this parameter, not 0 bytes.
*/
private final short assumedMinConcatBurst;
* @param transPolicy - the Requested Transmission Policy
* @param maxSusTrafficRate - the Maximum Sustained Traffic Rate
* @param maxTrafficBurst - the Maximum Traffic Burst Rate
- * @param minResTrafficRate - the Minimum Reserved Traffic Rate
- * @param assumedMinConcatBurst - the Assumed Minimum Reserved Traffic Rate Packet Size
+ * @param minResTrafficRate - the Minimum RESERVED Traffic Rate
+ * @param assumedMinConcatBurst - the Assumed Minimum RESERVED Traffic Rate Packet Size
* @param maxConcatBurst - the Maximum Concatenated Burst
* @param upPeakTrafficRate - the Upstream Peak Traffic Rate
* @param reqAttrMask - the Required Attribute Mask
protected BestEffortService(final byte envelope, final BEEnvelop auth, final BEEnvelop reserved,
final BEEnvelop committed) {
super(SNum.TRAFFIC_PROFILE, STYPE);
- if (auth == null) throw new IllegalArgumentException("Authorized envelope must not be null");
+ if (auth == null) throw new IllegalArgumentException("AUTHORIZED envelope must not be null");
// TODO - Cannot figure out any other means to parse the bytes unless this is true. Determine if correct???
if (reserved == null && committed != null)
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates.impl;
+
+import com.google.common.base.Objects;
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IGateState;
+import org.umu.cops.stack.COPSMsgParser;
+
+/**
+ * Implementation of the IGateID interface
+ */
+public class GateState extends PCMMBaseObject implements IGateState {
+
+ /**
+ * The Gate State value (unsigned 32 bit integer)
+ */
+ final GateStateType gateState;
+
+ /**
+ * The Gate State value (unsigned 32 bit integer)
+ */
+ final GateStateReasonType gateStateReason;
+
+ /**
+ * Constructor
+ */
+ public GateState(final GateStateType gateState, final GateStateReasonType gateStateReason) {
+ super(SNum.GATE_STATE, STYPE);
+ this.gateState = gateState;
+ this.gateStateReason = gateStateReason;
+ }
+
+ @Override
+ public GateStateType getGateState() {
+ return gateState;
+ }
+
+ @Override
+ public GateStateReasonType getGateStateReason() {
+ return gateStateReason;
+ }
+
+ @Override
+ protected byte[] getBytes() {
+ return COPSMsgParser.shortToBytes(gateState.getValue());
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof GateID)) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ final GateState gateSTATE = (GateState) o;
+ return gateState == gateSTATE.gateState;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), gateState, gateStateReason);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s/%s", gateState.toString(), gateStateReason.toString());
+ }
+
+ /**
+ * Returns a GateState object from a byte array
+ * @param data - the data to parse
+ * @return - the object
+ * TODO - make me more robust as RuntimeExceptions can be thrown here.
+ */
+ public static GateState parse(final byte[] data) {
+ return new GateState(GateStateType.valueOf(COPSMsgParser.bytesToShort(data[0], data[1])),
+ GateStateReasonType.valueOf(COPSMsgParser.bytesToShort(data[2], data[3])));
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates.impl;
+
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IGateTimeInfo;
+import org.umu.cops.stack.COPSMsgParser;
+
+/**
+ * Implementation of the IGateSpec interface
+ */
+public class GateTimeInfo extends PCMMBaseObject implements IGateTimeInfo {
+
+ final int gateTimeInfo;
+
+ public GateTimeInfo(final int gateTimeInfo) {
+ super(SNum.GATE_TIME_INFO, STYPE);
+ this.gateTimeInfo = gateTimeInfo;
+ }
+
+ @Override
+ public int getGateTimeInfo() {
+ return gateTimeInfo;
+ }
+
+
+ @Override
+ protected byte[] getBytes() {
+ return COPSMsgParser.intToBytes(gateTimeInfo);
+ }
+
+ public static GateTimeInfo parse(final byte[] data) {
+ return new GateTimeInfo((COPSMsgParser.bytesToInt(data[0], data[1],data[2], data[3])));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates.impl;
+
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IGateUsageInfo;
+import org.umu.cops.stack.COPSMsgParser;
+
+/**
+ * Implementation of the IGateSpec interface
+ */
+public class GateUsageInfo extends PCMMBaseObject implements IGateUsageInfo {
+
+ final long gateUsageInfo;
+
+ public GateUsageInfo(final long gateUsageInfo) {
+
+ super(SNum.GATE_USAGE_INFO, STYPE);
+ this.gateUsageInfo = gateUsageInfo;
+ }
+
+ @Override
+ public long getGateUsageInfo() {
+ return gateUsageInfo;
+ }
+
+
+
+ @Override
+ protected byte[] getBytes() {
+ byte[] first = COPSMsgParser.intToBytes((int)gateUsageInfo>>32);
+ byte[] second = COPSMsgParser.intToBytes((int)gateUsageInfo);
+ return new byte[first.length+second.length];
+ }
+
+ public static GateUsageInfo parse(final byte[] data) {
+ return new GateUsageInfo(
+ (long)(COPSMsgParser.bytesToInt(data[0], data[1],data[2], data[3]))<<32
+ | (COPSMsgParser.bytesToInt(data[4], data[5],data[6], data[7]))& 0xFFFFFFFFL);
+ }
+}
/**
* The error sub-code (defaults to NA)
*/
- private final ErrorCode subErrCode;
+ private final short subErrCode;
/**
* Constructor without a sub-code which will then be set to NA
* @param errorCode - the error code (required and not NA)
*/
public PCMMError(final ErrorCode errorCode) {
- this(errorCode, null);
+ this(errorCode, (short)0);
}
/**
* @param errorCode - the error code (required and not NA)
* @param subErrCode - the sub-code (defaults to NA when null)
*/
- public PCMMError(final ErrorCode errorCode, final ErrorCode subErrCode) {
+ public PCMMError(final ErrorCode errorCode, final short subErrCode) {
super(SNum.PCMM_ERROR, STYPE);
if (errorCode == null || errorCode.equals(ErrorCode.NA))
throw new IllegalArgumentException("ErrorCode is required and must not be NA");
this.errorCode = errorCode;
- if (subErrCode == null) this.subErrCode = ErrorCode.NA;
- else this.subErrCode = subErrCode;
+ this.subErrCode = subErrCode;
}
@Override
}
@Override
- public ErrorCode getErrorSubcode() {
+ public short getErrorSubcode() {
return subErrCode;
}
*/
@Override
public String getDescription() {
- String hex = Integer.toHexString(subErrCode.getCode() & 0xFFFF);
- return "Error Code: " + errorCode.getCode() + " Error Subcode : " + hex + " " + errorCode.getDescription();
+ //Error-Subcode is a 2-byte unsigned integer field used to provide further information about the error.
+ // In the case of Error-Codes 6, 7 and 17, this 16-bit field MUST contain, as two 8-bit values the
+ // S-Num and S-Type of the object that is missing or in error.
+ String subcode;
+ switch (errorCode) {
+ case MISSING_REQ_OBJ:
+ case INVALID_OBJ:
+ case INVALID_FIELD:
+ byte[] sParts = COPSMsgParser.shortToBytes(subErrCode);
+ subcode = String.format("S-Num: %d, S-Type: %d", sParts[0], sParts[1]);
+ break;
+ default:
+ subcode = "Subcode: " + Integer.toHexString(subErrCode & 0xFFFF);
+ }
+
+ return "Error Code: " + errorCode.getCode() + " " + subcode + " " + errorCode.getDescription();
}
@Override
@Override
protected byte[] getBytes() {
final byte[] errorCodeBytes = COPSMsgParser.shortToBytes(errorCode.getCode());
- final byte[] subErrCodeBytes = COPSMsgParser.shortToBytes(subErrCode.getCode());
+ final byte[] subErrCodeBytes = COPSMsgParser.shortToBytes(subErrCode);
final byte[] data = new byte[errorCodeBytes.length + subErrCodeBytes.length];
System.arraycopy(errorCodeBytes, 0, data, 0, errorCodeBytes.length);
System.arraycopy(subErrCodeBytes, 0, data, errorCodeBytes.length, subErrCodeBytes.length);
public int hashCode() {
int result = super.hashCode();
result = 31 * result + errorCode.hashCode();
- result = 31 * result + subErrCode.hashCode();
+ result = 31 * result + subErrCode;
return result;
}
*/
public static PCMMError parse(final byte[] data) {
return new PCMMError(ErrorCode.valueOf(COPSMsgParser.bytesToShort(data[0], data[1])),
- ErrorCode.valueOf((COPSMsgParser.bytesToShort(data[2], data[3]))));
+ (COPSMsgParser.bytesToShort(data[2], data[3])));
}
// synchronization purposes
private IGateID gateID;
private IPCMMError error;
+ private IGateState igateState;
+ private IGateTimeInfo gateTimeInfo;
+ private IGateUsageInfo gateUsageInfo;
/**
* Constructor
* @param error - the error
*/
public PCMMGateReq(IAMID iamid, ISubscriberID subscriberID, ITransactionID transactionID,
- IGateSpec gateSpec, ITrafficProfile trafficProfile, List<IClassifier> classifiers, IGateID gateID,
- IPCMMError error) {
+ IGateSpec gateSpec, ITrafficProfile trafficProfile, List<IClassifier> classifiers,
+ IGateID gateID,IPCMMError error,IGateState igateState,
+ IGateTimeInfo gateTimeInfo,IGateUsageInfo gateUsageInfo ) {
// TODO - determine if and when this attribute should be used
this.multicast = false;
this.classifiers = Lists.newArrayList(classifiers);
this.gateID = gateID;
this.error = error;
+ this.igateState = igateState;
+ this.gateTimeInfo = gateTimeInfo;
+ this.gateUsageInfo = gateUsageInfo;
}
/**
ITrafficProfile trafficProfile = null;
List<IClassifier> classifiers = Lists.newArrayListWithExpectedSize(4);
PCMMError error = null;
+ GateState gateState = null;
+ GateTimeInfo gateTimeInfo = null;
+ GateUsageInfo gateUsageInfo = null;
+
short offset = 0;
while (offset + 5 < data.length) {
case PCMM_ERROR:
error = PCMMError.parse(dataBuffer);
break;
+ //adding GATE_STATE
+ case GATE_STATE:
+ gateState = GateState.parse(dataBuffer);
+ break;
+ //adding GATE_TIME_INFO
+ case GATE_TIME_INFO:
+ gateTimeInfo = GateTimeInfo.parse(dataBuffer);
+ logger.info("Gate Time Info: "+gateTimeInfo);
+ break;
+ //adding GATE_USAGE_INFO
+ case GATE_USAGE_INFO:
+ gateUsageInfo = GateUsageInfo.parse(dataBuffer);
+ logger.info("Gate Usage Info: "+gateUsageInfo);
+ break;
default:
logger.warn("Unhandled Object skept : S-NUM=" + sNum
+ " S-TYPE=" + sType + " LEN=" + len);
offset += len;
}
- return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers, gateID, error);
+ return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile,
+ classifiers, gateID, error, gateState, gateTimeInfo,gateUsageInfo);
}
@Override
}
+ @Override
+ public void setGateState(IGateState gatestate) {
+ this.igateState = gatestate;
+ }
+
@Override
public void setTransactionID(ITransactionID transactionID) {
this.transactionID = transactionID;
this.trafficProfile = profile;
}
+ @Override
+ public void setGateTimeInfo(IGateTimeInfo gateTimeInfo) {
+ this.gateTimeInfo = gateTimeInfo;
+ }
+
+ @Override
+ public void setGateUsageInfo(IGateUsageInfo gateUsageInfo) {
+ this.gateUsageInfo = gateUsageInfo;
+ }
+
+
@Override
public IGateID getGateID() {
return gateID;
}
+ @Override
+ public IGateState getGateState() {
+ return igateState;
+ }
+
+
@Override
public IAMID getAMID() {
return iamid;
return error;
}
+ @Override
+ public IGateTimeInfo getGateTimeInfo() {
+ return gateTimeInfo;
+ }
+
+ @Override
+ public IGateUsageInfo getGateUsageInfo() {
+ return gateUsageInfo;
+ }
+
public void setError(IPCMMError error) {
this.error = error;
}
byteList.addAll(Bytes.asList(classifier.getAsBinaryArray()));
}
}
+ if (getGateState() != null) {
+ byteList.addAll(Bytes.asList(getGateState().getAsBinaryArray()));
+ }
+ if (getGateTimeInfo() != null) {
+ byteList.addAll(Bytes.asList(getGateTimeInfo().getAsBinaryArray()));
+ }
+ if (getGateUsageInfo() != null) {
+ byteList.addAll(Bytes.asList(getGateUsageInfo().getAsBinaryArray()));
+ }
return Bytes.toArray(byteList);
}
*/
public abstract class AbstractPCMMServer implements IPCMMServer {
- private final static Logger logger = LoggerFactory.getLogger(AbstractPCMMServer.class);
+ private static final Logger logger = LoggerFactory.getLogger(AbstractPCMMServer.class);
/*
* A ServerSocket to accept messages ( OPN requests)
return;
}
+
// Check message type
// TODO FIXME - Use of manager object could result in a NPE
if (decision.getFlag().equals(DecisionFlag.REQSTATE)) {
- if (decision.getCommand().equals(Command.REMOVE))
+ if (decision.getCommand().equals(Command.REMOVE)) {
// Delete Request State
manager.processDeleteRequestState(dMsg);
- else
+ } else if (decision.getCommand().equals(Command.INSTALL)) {
// Open new Request State
handleOpenNewRequestStateMsg(handle);
- } else
+ }
+ else {
+ logger.error("Unknown command");
+ }
+ } else {
// Decision
manager.processDecision(dMsg);
+ }
}
}
}
*/
private void handleOpenNewRequestStateMsg(final COPSHandle handle) throws COPSPepException {
final COPSPepReqStateMan manager = _managerMap.get(handle);
- if (manager == null)
+ if (manager == null) {
logger.warn("Unable to find state manager with key - " + handle.getId().str());
- else
+ } else {
manager.processOpenNewRequestState();
+ }
}
/**
}
final COPSPepReqStateMan manager = _managerMap.get(cMsg.getClientHandle());
- if (manager == null)
+ if (manager == null) {
logger.warn("Unable to find state manager with key - " + cMsg.getClientHandle().getId().str());
- else
+ } else {
manager.processSyncStateRequest(cMsg);
+ }
}
/**
@Test(expected = IllegalArgumentException.class)
public void nullErrorAndSubCodes() {
- new PCMMError(null, null);
+ new PCMMError(null, (short)0);
}
@Test(expected = IllegalArgumentException.class)
public void nullErrorCode() {
- new PCMMError(null, ErrorCode.DOCSIS_1_CM);
+ new PCMMError(null, (short)0);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void construction() {
- final PCMMError error = new PCMMError(ErrorCode.TRANSPORT_ERROR, null);
+ final PCMMError error = new PCMMError(ErrorCode.TRANSPORT_ERROR, (short)0);
Assert.assertEquals(ErrorCode.TRANSPORT_ERROR, error.getErrorCode());
- Assert.assertEquals(ErrorCode.NA, error.getErrorSubcode());
+ Assert.assertEquals(ErrorCode.NA.getCode(), error.getErrorSubcode());
final byte[] dataBytes = error.getBytes();
Assert.assertEquals(4, dataBytes.length);
@Test
public void byteParsing() {
- final PCMMError error = new PCMMError(ErrorCode.INVALID_FIELD, ErrorCode.INVALID_SUB_ID);
+ final PCMMError error = new PCMMError(ErrorCode.INVALID_FIELD, ErrorCode.INVALID_SUB_ID.getCode());
final PCMMError parsed = PCMMError.parse(error.getBytes());
Assert.assertEquals(error, parsed);
}
# The CMTS Emulator's communications port number
port: 3918
+numberOfSupportedClassifiers: 4
-# The configured gates
-gates:
- - type: UPSTREAM
+# The configured service class names
+serviceClassNames:
+ - direction: UPSTREAM
names:
- extrm_up
- foo_up
- - type: DOWNSTREAM
+ - direction: DOWNSTREAM
names:
- extrm_dn
- foo_dn
package org.pcmm.rcd.impl;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import org.pcmm.gates.IGateSpec.Direction;
-import org.pcmm.rcd.ICMTS;
+import static com.google.common.base.Preconditions.checkNotNull;
-import java.io.FileInputStream;
+import com.google.common.collect.Maps;
import java.io.IOException;
import java.net.Socket;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+import org.pcmm.rcd.ICMTS;
/**
* Mock CMTS that can be used for testing. startServer() is called to start required threads after instantiation.
*/
public class CMTS extends AbstractPCMMServer implements ICMTS {
+ /**
+ * Emulator configuration
+ */
+ private final CMTSConfig config;
+
/**
* Receives messages from the COPS client
*/
private final Map<String, IPCMMClientHandler> handlerMap;
- /**
- * The configured gates
- */
- private final Map<Direction, Set<String>> gateConfig;
-
- /**
- * The connected CMTSs and whether or not they are up
- */
- private final Map<String, Boolean> cmStatus;
-
/**
* Constructor for having the server port automatically assigned
* Call getPort() after startServer() is called to determine the port number of the server
*/
- public CMTS(final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
- this(0, gateConfig, cmStatus);
- }
-
- /**
- * Constructor for starting the server to a pre-defined port number
- * @param port - the port number on which to start the server.
- */
- public CMTS(final int port, final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
- super(port);
- if (gateConfig == null || cmStatus == null) throw new IllegalArgumentException("Config must not be null");
- this.gateConfig = Collections.unmodifiableMap(gateConfig);
- this.cmStatus = Collections.unmodifiableMap(cmStatus);
- handlerMap = new ConcurrentHashMap<>();
- }
+ public CMTS(final CMTSConfig config) {
+ super(checkNotNull(config, "config must not be null").getPort());
+ this.config = config;
+ handlerMap = Maps.newConcurrentMap();
+ }
@Override
public void stopServer() {
protected IPCMMClientHandler getPCMMClientHandler(final Socket socket) throws IOException {
final String key = socket.getLocalAddress().getHostName() + ':' + socket.getPort();
if (handlerMap.get(key) == null) {
- final IPCMMClientHandler handler = new CmtsPcmmClientHandler(socket, gateConfig, cmStatus);
+ final IPCMMClientHandler handler = new CmtsPcmmClientHandler(socket, config);
handler.connect();
handlerMap.put(key, handler);
return handler;
- } else return handlerMap.get(key);
+ } else {
+ return handlerMap.get(key);
+ }
}
/**
* @throws IOException - should the server fail to start for reasons such as port contention.
*/
public static void main(final String[] args) throws IOException {
- final CmtsYaml config = getConfig(args[0]);
- final CMTS cmts = new CMTS(config.port, config.getGates(), config.getCmStatus());
- cmts.startServer();
- }
-
- /**
- * Returns the object that represents the YAML file
- * @param uri - the location of the YAML file
- * @return - the config object
- * @throws IOException - when the URI does not contain the proper YAML file
- */
- private static CmtsYaml getConfig(final String uri) throws IOException {
- final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
- return mapper.readValue(new FileInputStream(uri), CmtsYaml.class);
- }
-
- /**
- * Class to hold configuration settings in a YAML file
- */
- public static class CmtsYaml {
- @JsonProperty("port")
- private int port;
-
- @JsonProperty("gates")
- private Collection<GateConfigYaml> gateConfigs;
-
- @JsonProperty("cmStatuses")
- private Collection<CmStatusYaml> cmStatuses;
-
- public Map<Direction, Set<String>> getGates() {
- final Map<Direction, Set<String>> out = new HashMap<>();
-
- for (final GateConfigYaml gateConfig : gateConfigs) {
- final Direction direction;
- if (gateConfig.gateType.equalsIgnoreCase("UPSTREAM")) {
- direction = Direction.UPSTREAM;
- } else if (gateConfig.gateType.equalsIgnoreCase("DOWNSTREAM")) {
- direction = Direction.DOWNSTREAM;
- } else direction = null;
+ if (args.length != 1) {
+ throw new IllegalArgumentException("expected arguments: <cmts_yaml_config_file>");
+ }
- if (direction != null) {
- out.put(direction, gateConfig.gateNames);
- }
- }
- return out;
- }
-
- public Map<String, Boolean> getCmStatus() {
- final Map<String, Boolean> out = new HashMap<>();
-
- for (final CmStatusYaml cmStatus : cmStatuses) {
- out.put(cmStatus.hostIp, cmStatus.status);
- }
- return out;
- }
- }
-
- /**
- * Class to hold the YAML gate configuration values
- */
- public static class GateConfigYaml {
- @JsonProperty("type")
- private String gateType;
-
- @JsonProperty("names")
- private Set<String> gateNames;
- }
-
- /**
- * Class to hold the YAML Cable Modem configuration values
- */
- public static class CmStatusYaml {
- @JsonProperty("host")
- private String hostIp;
-
- @JsonProperty("status")
- private boolean status;
+ final CMTSConfig config = CMTSConfig.loadConfig(args[0]);
+ final CMTS cmts = new CMTS(config);
+ cmts.startServer();
}
}
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.rcd.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import org.pcmm.gates.IGateSpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class to hold configuration settings in a YAML file
+ */
+public class CMTSConfig {
+
+ private static final Logger logger = LoggerFactory.getLogger(CMTSConfig.class);
+
+ /**
+ * Returns the object that represents the YAML file
+ * @param uri - the location of the YAML file
+ * @return - the config object
+ * @throws IOException - when the URI does not contain the proper YAML file
+ */
+ public static CMTSConfig loadConfig(final String uri) throws IOException {
+ final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+ final CmtsYmal cmtsYmal = mapper.readValue(new FileInputStream(uri), CmtsYmal.class);
+
+ final Map<IGateSpec.Direction, Set<String>> scns = cmtsYmal.getServiceClassNames();
+
+ final Set<String> upstreamSCNs = scns.containsKey(IGateSpec.Direction.UPSTREAM)
+ ? scns.get(IGateSpec.Direction.UPSTREAM)
+ : Collections.<String>emptySet();
+
+ final Set<String> downstreamSCNs = scns.containsKey(IGateSpec.Direction.DOWNSTREAM)
+ ? scns.get(IGateSpec.Direction.DOWNSTREAM)
+ : Collections.<String>emptySet();
+
+ if (upstreamSCNs.isEmpty() && downstreamSCNs.isEmpty()) {
+ logger.error("No upstream or downstream service class names defined in config");
+ }
+
+ return new CMTSConfig(cmtsYmal.getPort(),
+ cmtsYmal.getNumberOfSupportedClassifiers(),
+ upstreamSCNs,
+ downstreamSCNs,
+ cmtsYmal.getCmStatus());
+ }
+
+ private final int port;
+
+ private final short numberOfSupportedClassifiers;
+
+ private final ImmutableSet<String> upstreamServiceClassNames;
+
+ private final ImmutableSet<String> downstreamServiceClassNames;
+
+ private final ImmutableMap<String, Boolean> modemStatus;
+
+ public CMTSConfig(final int port, final short numberOfSupportedClassifiers,
+ final Set<String> upstreamServiceClassNames, final Set<String> downstreamServiceClassNames,
+ final Map<String, Boolean> modemStatus) {
+ checkNotNull(upstreamServiceClassNames, "upstreamServiceClassNames must not be null");
+ checkNotNull(downstreamServiceClassNames, "downstreamServiceClassNames must not be null");
+ checkNotNull(modemStatus, "modemStatus must not be null");
+
+ this.port = port;
+ this.numberOfSupportedClassifiers = numberOfSupportedClassifiers;
+ this.upstreamServiceClassNames = ImmutableSet.copyOf(upstreamServiceClassNames);
+ this.downstreamServiceClassNames = ImmutableSet.copyOf(downstreamServiceClassNames);
+ this.modemStatus = ImmutableMap.copyOf(modemStatus);
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public short getNumberOfSupportedClassifiers() {
+ return numberOfSupportedClassifiers;
+ }
+
+ public ImmutableSet<String> getUpstreamServiceClassNames() {
+ return upstreamServiceClassNames;
+ }
+
+ public ImmutableSet<String> getDownstreamServiceClassNames() {
+ return downstreamServiceClassNames;
+ }
+
+ public ImmutableMap<String, Boolean> getModemStatus() {
+ return modemStatus;
+ }
+}
final ITransactionID transactionID = PCMMGateReq.parse(new COPSData(data).getData()).getTransactionID();
// TODO - Determine how and why a response gate request can have only a transaction ID???
- final IPCMMGate responseGate = new PCMMGateReq(null, null, transactionID, null, null, null, null, null);
+ final IPCMMGate responseGate = new PCMMGateReq(null, null, transactionID, null, null, null, null, null, null, null, null);
// TODO FIXME - Why is the key always null??? What value should be used here???
final String key = null;
package org.pcmm.rcd.impl;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import org.pcmm.gates.IGateSpec.Direction;
import org.pcmm.messages.impl.MessageFactory;
import org.pcmm.rcd.IPCMMServer.IPCMMClientHandler;
*/
public class CmtsPcmmClientHandler extends AbstractPCMMClient implements IPCMMClientHandler {
- private final static Logger logger = LoggerFactory.getLogger(CmtsPcmmClientHandler.class);
+ private static final Logger logger = LoggerFactory.getLogger(CmtsPcmmClientHandler.class);
/**
* The thread accepting PEP COPS messages
private transient Thread thread;
/**
- * The configured gates
- */
- private final Map<Direction, Set<String>> gateConfig;
-
- /**
- * The connected cable modems and whether or not they are up
+ * Emulator configuration
*/
- private final Map<String, Boolean> cmStatus;
+ private final CMTSConfig config;
/**
* Constructor when a socket connection has not been established
* @param host - the host to connect
* @param port - the port to connect
- * @param gateConfig - the configured gates
- * @param cmStatus - the configured cable modem and their state
+ * @param config - emulator configuration
*/
- public CmtsPcmmClientHandler(final String host, final int port, final Map<Direction, Set<String>> gateConfig,
- final Map<String, Boolean> cmStatus) {
+ public CmtsPcmmClientHandler(final String host, final int port, final CMTSConfig config) {
super(host, port);
- this.gateConfig = Collections.unmodifiableMap(gateConfig);
- this.cmStatus = Collections.unmodifiableMap(cmStatus);
+ this.config = checkNotNull(config);
}
/**
* Constructor with a connected socket.
* @param socket - the socket connection
- * @param gateConfig - the configured gates
- * @param cmStatus - the configured cable modem and their state
+ * @param config - emulator configuration
*/
- public CmtsPcmmClientHandler(final Socket socket, final Map<Direction, Set<String>> gateConfig,
- final Map<String, Boolean> cmStatus) {
+ public CmtsPcmmClientHandler(final Socket socket, final CMTSConfig config) {
super(socket);
- this.gateConfig = Collections.unmodifiableMap(gateConfig);
- this.cmStatus = Collections.unmodifiableMap(cmStatus);
+ this.config = checkNotNull(config);
}
public void stop() {
final COPSKATimer kt = acceptMsg.getKATimer();
if (kt == null)
throw new COPSPepException("Mandatory COPS object missing (KA Timer)");
- short kaTimeVal = kt.getTimerVal();
+ final short kaTimeVal = kt.getTimerVal();
// ACTimer
final COPSAcctTimer at = acceptMsg.getAcctTimer();
sendRequest(reqMsg);
// Create the connection manager
- final PcmmCmtsConnection conn = new PcmmCmtsConnection(CLIENT_TYPE, getSocket(), gateConfig,
- cmStatus);
+ final PcmmCmtsConnection conn = new PcmmCmtsConnection(CLIENT_TYPE, getSocket(), config);
conn.addRequestState(handle, new CmtsDataProcessor());
conn.setKaTimer(kaTimeVal);
conn.setAcctTimer(acctTimer);
package org.pcmm.rcd.impl;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+import com.google.common.primitives.Bytes;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+import java.util.Vector;
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IAMID;
+import org.pcmm.gates.IClassifier;
+import org.pcmm.gates.IGateID;
+import org.pcmm.gates.IGateSpec;
import org.pcmm.gates.IGateSpec.Direction;
+import org.pcmm.gates.IGateState;
import org.pcmm.gates.IPCMMError;
import org.pcmm.gates.IPCMMError.ErrorCode;
+import org.pcmm.gates.ISubscriberID;
+import org.pcmm.gates.ITransactionID;
+import org.pcmm.gates.impl.AMID;
+import org.pcmm.gates.impl.DOCSISServiceClassNameTrafficProfile;
import org.pcmm.gates.impl.GateID;
+import org.pcmm.gates.impl.GateSpec;
+import org.pcmm.gates.impl.GateState;
+import org.pcmm.gates.impl.GateTimeInfo;
+import org.pcmm.gates.impl.GateUsageInfo;
import org.pcmm.gates.impl.PCMMError;
import org.pcmm.gates.impl.PCMMGateReq;
+import org.pcmm.gates.impl.TransactionID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.umu.cops.prpep.COPSPepException;
import org.umu.cops.prpep.COPSPepMsgSender;
import org.umu.cops.prpep.COPSPepReqStateMan;
-import org.umu.cops.stack.*;
+import org.umu.cops.stack.COPSClientSI;
+import org.umu.cops.stack.COPSContext;
+import org.umu.cops.stack.COPSData;
+import org.umu.cops.stack.COPSDecision;
import org.umu.cops.stack.COPSDecision.DecisionFlag;
+import org.umu.cops.stack.COPSDecisionMsg;
+import org.umu.cops.stack.COPSException;
+import org.umu.cops.stack.COPSHandle;
+import org.umu.cops.stack.COPSMsgParser;
import org.umu.cops.stack.COPSObjHeader.CNum;
import org.umu.cops.stack.COPSObjHeader.CType;
+import org.umu.cops.stack.COPSReportMsg;
+import org.umu.cops.stack.COPSReportType;
import org.umu.cops.stack.COPSReportType.ReportType;
-import java.io.IOException;
-import java.net.Socket;
-import java.util.*;
-
/**
* PEP State manager implementation for use in a CMTS.
*/
public class CmtsPepReqStateMan extends COPSPepReqStateMan {
- private final static Logger logger = LoggerFactory.getLogger(CmtsPepReqStateMan.class);
+ private static final Logger logger = LoggerFactory.getLogger(CmtsPepReqStateMan.class);
- /**
- * The configured gates
- */
- private final Map<Direction, Set<String>> gateConfig;
+ private final CMTSConfig config;
- /**
- * The connected CMTSs and whether or not they are up
- */
- private final Map<String, Boolean> cmStatus;
+ private final Map<IGateID, GateMetaData> gateStateMap;
- /**
- * Contains the gates that have been set where the key is the gate name and the value is a Set of subIds
- * that are using this gate
- */
- private final Map<String, Set<String>> gatesSetMap;
+ private static class GateMetaData {
+
+ private final PCMMGateReq gateReq;
+ private long commitTime;
+ private long kiloBytesTransmitted;
+
+ private Random random;
+
+ public GateMetaData(final PCMMGateReq gateReq) {
+ this.gateReq = checkNotNull(gateReq);
+ updateCommitTime();
+ kiloBytesTransmitted = 0;
+ this.random = new Random(gateReq.getGateID().getGateID());
+ }
+
+ public long updateCommitTime() {
+ commitTime = System.currentTimeMillis() / 1000L;
+ return commitTime;
+ }
+
+ public PCMMGateReq getGateReq() {
+ return gateReq;
+ }
+
+ public long getCommitTime() {
+ return commitTime;
+ }
+
+ public int getCommitDuration() {
+ return (int)((System.currentTimeMillis() / 1000L) - commitTime);
+ }
+
+ public long updateKiloBytesTransmitted() {
+ kiloBytesTransmitted += random.nextInt(2000);
+ return kiloBytesTransmitted;
+ }
+
+ public long getKiloBytesTransmitted() {
+ return kiloBytesTransmitted;
+ }
+ }
+
+ private static class GateKey {
+ private IAMID amID;
+ private ISubscriberID subscriberID;
+ private IGateID gateID;
+
+ public GateKey(final IAMID amID, final ISubscriberID subscriberID, final IGateID gateID) {
+ this.amID = checkNotNull(amID);
+ this.subscriberID = checkNotNull(subscriberID);
+ this.gateID = checkNotNull(gateID);
+ }
+
+ public IAMID getAmID() {
+ return amID;
+ }
+
+ public ISubscriberID getSubscriberID() {
+ return subscriberID;
+ }
+
+ public IGateID getGateID() {
+ return gateID;
+ }
+
+ public boolean matches(final AMID otherAMID, final ISubscriberID otherSubscriberID) {
+ checkNotNull(otherAMID);
+ checkNotNull(otherSubscriberID);
+
+ return Objects.equal(amID, otherAMID) && Objects.equal(subscriberID, otherSubscriberID);
+
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final GateKey otherGateKey = (GateKey) o;
+ return Objects.equal(amID, otherGateKey.amID) &&
+ Objects.equal(subscriberID, otherGateKey.subscriberID) &&
+ Objects.equal(gateID, otherGateKey.gateID);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(amID, subscriberID, gateID);
+ }
+ }
/**
* Create a State Request Manager
*
- * @param clientType - the client type for this connection
- * @param clientHandle - the client-handle for this connection
- * @param process - the data processor
- * @param socket - the socket connection
- * @param gateConfig - the configured service class names (gates)
+ * @param clientType
+ * - the client type for this connection
+ * @param clientHandle
+ * - the client-handle for this connection
+ * @param process
+ * - the data processor
+ * @param socket
+ * - the socket connection
*/
public CmtsPepReqStateMan(final short clientType, final COPSHandle clientHandle, final CmtsDataProcessor process,
- final Socket socket, final Map<Direction, Set<String>> gateConfig,
- final Map<String, Boolean> cmStatus) {
+ final Socket socket, final CMTSConfig config) {
super(clientType, clientHandle, process, socket, new COPSPepMsgSender(clientType, clientHandle, socket));
- this.gateConfig = Collections.unmodifiableMap(gateConfig);
- this.cmStatus = Collections.unmodifiableMap(cmStatus);
-
- this.gatesSetMap = new HashMap<>();
- for (final Set<String> gateIdSet: gateConfig.values()) {
- for (final String gateId : gateIdSet) {
- gatesSetMap.put(gateId, new HashSet<String>());
- }
- }
+ this.config = checkNotNull(config);
+ gateStateMap = new HashMap<>();
}
@Override
final Map<String, String> removeDecs = new HashMap<>();
final Map<String, String> installDecs = new HashMap<>();
- for (final Set<COPSDecision> copsDecisions: decisions.values()) {
+ for (final Set<COPSDecision> copsDecisions : decisions.values()) {
final COPSDecision cmddecision = copsDecisions.iterator().next();
+ logger.debug("decision command: " + cmddecision.getCommand());
switch (cmddecision.getCommand()) {
case INSTALL:
for (final COPSDecision decision : copsDecisions) {
if (decision.getFlag().equals(DecisionFlag.REQERROR)) {
- logger.info("processing decision");
+ logger.info("processing decision: " + dMsg.getDecSI());
// This is assuming a gate set right or wrong
if (dMsg.getDecisions().size() == 1 && dMsg.getDecSI() != null) {
final PCMMGateReq gateReq = PCMMGateReq.parse(dMsg.getDecSI().getData().getData());
- if (gateReq.getGateSpec() != null) {
+ if (gateReq != null) {
processGateReq(gateReq, _socket);
}
+ else {
+ logger.error("gateReq failed to parse");
+ }
}
}
}
// TODO - Check and/or Set state here
// Gate ADD gateReq.getTrafficProfile() != null
// Gate REMOVE gateReq.getTrafficProfile() == null
- final String subId = gateReq.getSubscriberID().getSourceIPAddress().getHostAddress();
- // Get direction here
+ switch (gateReq.getTransactionID().getGateCommandType()) {
+ case GATE_SET:
+ processGateSet(gateReq, socket);
+ break;
+ case GATE_INFO:
+ processGateInfo(gateReq, socket);
+ break;
+ default:
+ logger.error("Emulator does not support gate command: {}",
+ gateReq.getTransactionID().getGateCommandType());
+ }
+
+ }
+
+
+ private IPCMMError checkForMissingObjects(final PCMMGateReq gateReq) {
+ // In cases where multiple valid alternatives exist for the S-Type of a missing object,
+ // this portion of the Error-Subcode MUST be set to zero.
+
+ if (gateReq.getTransactionID() == null) {
+ final short subCode =
+ COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.TRANSACTION_ID.getValue(), TransactionID.STYPE);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+
+ final ITransactionID.GateCommandType gateCommand = gateReq.getTransactionID().getGateCommandType();
+
+ if (gateCommand == ITransactionID.GateCommandType.GATE_SET) {
+ // Gate set does not allow gateID
+ if (gateReq.getGateID() != null) {
+ final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.GATE_ID.getValue(), GateID.STYPE);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+
+ if (gateReq.getTrafficProfile() == null) {
+ final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.TRAFFIC_PROFILE.getValue(), (byte) 0);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+
+ if (gateReq.getClassifiers() == null || gateReq.getClassifiers().isEmpty()) {
+ final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.CLASSIFIERS.getValue(), (byte) 0);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+
+ if (gateReq.getGateSpec() == null) {
+ final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.GATE_SPEC.getValue(), GateSpec.STYPE);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+
+ final IGateSpec gateSpec = gateReq.getGateSpec();
+ if (gateSpec.getDirection() == null) {
+ return new PCMMError(ErrorCode.INVALID_FIELD);
+ }
+
+ }
+ else {
+
+ if (gateReq.getGateID() == null) {
+ final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.GATE_ID.getValue(), GateID.STYPE);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+ }
+
+ if (gateReq.getAMID() == null) {
+ final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.AMID.getValue(), AMID.STYPE);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+
+ if (gateReq.getSubscriberID() == null || gateReq.getSubscriberID().getSourceIPAddress() == null
+ || gateReq.getSubscriberID().getSourceIPAddress().getHostAddress() == null) {
+ final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.SUBSCRIBER_ID.getValue(), (byte) 0);
+ return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+ }
+
+
+ return null;
+ }
+
+ private IPCMMError checkForInvalidObjects(final PCMMGateReq gateReq) {
+ final ITransactionID.GateCommandType gateCommand = gateReq.getTransactionID().getGateCommandType();
+
+ // GateID
+ if (gateCommand == ITransactionID.GateCommandType.GATE_INFO) {
+ if (!gateStateMap.containsKey(gateReq.getGateID())) {
+ return new PCMMError(ErrorCode.UNK_GATE_ID);
+ }
+ }
+ else {
+ // Traffic profile
+
+ if (gateReq.getTrafficProfile() instanceof DOCSISServiceClassNameTrafficProfile) {
+ final DOCSISServiceClassNameTrafficProfile scnTrafficProfile =
+ (DOCSISServiceClassNameTrafficProfile) gateReq.getTrafficProfile();
+
+ Set<String> directionSCNs;
+ if (gateReq.getGateSpec().getDirection().equals(Direction.DOWNSTREAM)) {
+ directionSCNs = config.getDownstreamServiceClassNames();
+ } else {
+ directionSCNs = config.getUpstreamServiceClassNames();
+ }
+ if (!directionSCNs.contains(scnTrafficProfile.getScnName())) {
+ return new PCMMError(ErrorCode.UNDEF_SCN_NAME);
+ }
+ } else {
+ // TODO remote this after other profiles are supported
+ logger.error("Currently only DOCSIS Service Class Name Traffic Profiles are supported: attempted {}",
+ gateReq.getTrafficProfile().getClass().getName());
+ return new PCMMError(ErrorCode.OTHER_UNSPECIFIED);
+ }
+
+ // number of classifiers
+ if (config.getNumberOfSupportedClassifiers() < gateReq.getClassifiers().size()) {
+ return new PCMMError(ErrorCode.NUM_CLASSIFIERS, config.getNumberOfSupportedClassifiers());
+ }
+ }
+
+
+
+ // SubscriberID
+ String subId = gateReq.getSubscriberID().getSourceIPAddress().getHostAddress();
+ if(!config.getModemStatus().containsKey(subId) || !config.getModemStatus().get(subId)) {
+ return new PCMMError(ErrorCode.INVALID_SUB_ID);
+ }
+
+ // Iff the gate exists
+ if (gateReq.getGateID() != null
+ && gateStateMap.containsKey(gateReq.getGateID())) {
+ GateMetaData existingGate = gateStateMap.get(gateReq.getGateID());
+
+ // Unauthorized AMID - only the AM that created a gate may change it
+ if (!existingGate.getGateReq().getAMID().equals(gateReq.getAMID())) {
+ return new PCMMError(ErrorCode.UNAUTH_AMID);
+ }
+ }
+
+
+
+
+ return null;
+ }
+
+ private IPCMMError getGateError(final PCMMGateReq gateReq) {
+
+ IPCMMError error = null;
+ error = checkForMissingObjects(gateReq);
+ if (error != null) {
+ return error;
+ }
+
+ error = checkForInvalidObjects(gateReq);
+ if (error != null) {
+ return error;
+ }
+
+
+ return null;
+ }
+
+ private void processGateSet(final PCMMGateReq gateReq, final Socket socket) throws COPSException {
+
+ final String subId = gateReq.getSubscriberID().getSourceIPAddress().getHostAddress();
final Direction gateDir = gateReq.getGateSpec().getDirection();
- final Set<String> gateNames = gateConfig.get(gateDir);
- // TODO - Determine if this is the best means to derive the gate name???
- final String gateName = new String(gateReq.getTrafficProfile().getAsBinaryArray());
-
- final IPCMMError error;
- if (subId == null || gateDir == null || gateNames == null) {
- // Missing required object
- // TODO - Determine if this is the correct code. 3 was being used previously and I don't see any corresponding code.
- error = new PCMMError(ErrorCode.UNK_GATE_ID);
- } else if (!cmStatus.keySet().contains(subId)
- || (cmStatus.keySet().contains(subId) && !cmStatus.get(subId))) {
- // Invalid Object
- // TODO - Determine if this code is correct
- error = new PCMMError(ErrorCode.INVALID_SUB_ID);
- } else if (!gateNames.contains(gateName.trim())) {
- // TODO - Determine if this code is correct
- error = new PCMMError(ErrorCode.UNDEF_SCN_NAME);
+
+ final String serviceClassName;
+ if ((gateReq.getTrafficProfile() instanceof DOCSISServiceClassNameTrafficProfile)) {
+ serviceClassName = ((DOCSISServiceClassNameTrafficProfile) gateReq.getTrafficProfile()).getScnName();
} else {
- error = null;
- gatesSetMap.get(gateName.trim()).add(subId);
+ serviceClassName = null;
}
- gateReq.setError(error);
- logger.info("Processing gate request [" + gateName + "] with direction [" + gateDir + ']');
+ final IPCMMError error = getGateError(gateReq);
+ gateReq.setError(error);
- // Get gate name
+ logger.info("Processing gate set request [" + serviceClassName + "] with direction [" + gateDir + ']');
// Set response
+
+ final ITransactionID.GateCommandType gateCommand = (error == null)
+ ? ITransactionID.GateCommandType.GATE_SET_ACK
+ : ITransactionID.GateCommandType.GATE_SET_ERR;
+
+ final TransactionID transactionID =
+ new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(), gateCommand);
+
final List<Byte> data = new ArrayList<>();
- for (final byte val : gateReq.getTransactionID().getAsBinaryArray())
- data.add(val);
- for (final byte val : gateReq.getAMID().getAsBinaryArray())
- data.add(val);
- for (final byte val : gateReq.getSubscriberID().getAsBinaryArray())
- data.add(val);
- if (error != null) for (final byte val : gateReq.getError().getAsBinaryArray())
- data.add(val);
+ addBytesToList(transactionID.getAsBinaryArray(), data);
+ addBytesToList(gateReq.getAMID().getAsBinaryArray(), data);
+ addBytesToList(gateReq.getSubscriberID().getAsBinaryArray(), data);
- // Assign a gate ID
- final GateID gateID = new GateID(UUID.randomUUID().hashCode());
- for (final byte val : gateID.getAsBinaryArray())
- data.add(val);
+ if (error == null) {
+ // Assign a gate ID
+ final GateID gateID = new GateID(UUID.randomUUID().hashCode());
+ for (final byte val : gateID.getAsBinaryArray()) {
+ data.add(val);
+ }
+ gateReq.setGateID(gateID);
+
+ int timeStamp = (int)(System.currentTimeMillis() / 1000L);
+ gateReq.setGateTimeInfo(new GateTimeInfo(timeStamp));
- final byte[] csiArr = new byte[data.size()];
- for (int i = 0; i < data.size(); i++) {
- csiArr[i] = data.get(i);
+ gateStateMap.put(gateID, new GateMetaData(gateReq));
+ }
+ else {
+ addBytesToList(error.getAsBinaryArray(), data);
}
+
+ final byte[] csiArr = Bytes.toArray(data);
final COPSClientSI si = new COPSClientSI(CNum.CSI, CType.DEF, new COPSData(csiArr, 0, csiArr.length));
final ReportType reportType;
- if (gateReq.getError() == null) reportType = ReportType.SUCCESS; else reportType = ReportType.FAILURE;
+ if (gateReq.getError() == null) {
+ reportType = ReportType.SUCCESS;
+ } else {
+ reportType = ReportType.FAILURE;
+ }
- logger.info("Returning " + reportType + " for gate request [" + gateName + "] direction [" + gateDir
+ logger.info("Returning " + reportType + " for gate request [" + serviceClassName + "] direction [" + gateDir
+ "] for host - " + subId);
- final COPSReportMsg reportMsg = new COPSReportMsg(_clientType, getClientHandle(),
- new COPSReportType(reportType), si, null);
+ sendReport(reportType, si, socket);
+
+ }
+
+ private void processGateInfo(final PCMMGateReq gateReq, final Socket socket) throws COPSException {
+ logger.info("GateInfo");
+
+ IPCMMError error = getGateError(gateReq);
+
+ final TransactionID transactionID;
+ final ReportType reportType;
+ if (error != null) {
+ transactionID = new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
+ ITransactionID.GateCommandType.GATE_INFO_ERR);
+ reportType = ReportType.FAILURE;
+ }
+ else {
+ transactionID = new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
+ ITransactionID.GateCommandType.GATE_INFO_ACK);
+ reportType = ReportType.SUCCESS;
+ }
+
+ final List<Byte> data = new ArrayList<>();
+ addBytesToList(transactionID.getAsBinaryArray(), data);
+ addBytesToList(gateReq.getAMID().getAsBinaryArray(), data);
+ addBytesToList(gateReq.getSubscriberID().getAsBinaryArray(), data);
+ addBytesToList(gateReq.getGateID().getAsBinaryArray(), data);
+
+ if (error != null) {
+ addBytesToList(error.getAsBinaryArray(), data);
+ }
+ else {
+ GateMetaData exisitingGate = gateStateMap.get(gateReq.getGateID());
+
+ addBytesToList(exisitingGate.getGateReq().getGateSpec().getAsBinaryArray(), data);
+
+ for (IClassifier classifier : exisitingGate.getGateReq().getClassifiers()) {
+ addBytesToList(classifier.getAsBinaryArray(), data);
+ }
+
+ addBytesToList(exisitingGate.getGateReq().getTrafficProfile().getAsBinaryArray(), data);
+
+ GateTimeInfo timeInfo = new GateTimeInfo(exisitingGate.getCommitDuration());
+ addBytesToList(timeInfo.getAsBinaryArray(), data);
+
+ GateUsageInfo gateUsageInfo = new GateUsageInfo(exisitingGate.updateKiloBytesTransmitted());
+ addBytesToList(gateUsageInfo.getAsBinaryArray(), data);
+
+ GateState gateState = new GateState(IGateState.GateStateType.COMMITTED,
+ IGateState.GateStateReasonType.OTHER);
+ addBytesToList(gateState.getAsBinaryArray(), data);
+
+ logger.info("Returning " + reportType + " for gate info request on gate " + exisitingGate.getGateReq().getGateID() );
+ }
+
+ final byte[] csiArr = Bytes.toArray(data);
+ COPSClientSI copsClientSI = new COPSClientSI(CNum.CSI, CType.DEF, new COPSData(csiArr, 0, csiArr.length));
+
+ sendReport(reportType, copsClientSI, socket);
+ }
+
+ private void sendReport(ReportType reportType, COPSClientSI copsClientSI, final Socket socket)
+ throws COPSPepException {
+ logger.info("Returning {} for gate request", reportType);
+
+ final COPSReportMsg reportMsg =
+ new COPSReportMsg(_clientType, getClientHandle(), new COPSReportType(reportType), copsClientSI, null);
try {
reportMsg.writeData(socket);
} catch (IOException e) {
throw new COPSPepException("Error writing gate set SUCCESS Report", e);
}
+
+ }
+
+ private static void addBytesToList(byte[] array, List<Byte> list) {
+ checkNotNull(array);
+ checkNotNull(list);
+
+ if (array.length == 0) return;
+
+ // if list supports resizing do so
+ if (list instanceof ArrayList) {
+ ArrayList<Byte> arrayList = (ArrayList<Byte>) list;
+ arrayList.ensureCapacity(list.size() + array.length);
+ }
+ else if (list instanceof Vector){
+ Vector<Byte> vector = (Vector<Byte>) list;
+ vector.ensureCapacity(vector.size() + array.length);
+ }
+
+ // Add all
+ for (byte b : array) {
+ list.add(b);
+ }
}
}
--- /dev/null
+/*
+ * Copyright (c) 2015 CableLabs and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.rcd.impl;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.pcmm.gates.IGateSpec;
+
+/**
+ * @author rvail
+ */
+public class CmtsYmal {
+ @JsonProperty("port")
+ private int port;
+
+ @JsonProperty("numberOfSupportedClassifiers")
+ private short numberOfSupportedClassifiers;
+
+ @JsonProperty("serviceClassNames")
+ private Collection<ServiceClassNamesYaml> serviceClassNames;
+
+ @JsonProperty("cmStatuses")
+ private Collection<CmStatusYaml> cmStatuses;
+
+ public int getPort() {
+ return port;
+ }
+
+ public short getNumberOfSupportedClassifiers() {
+ return numberOfSupportedClassifiers;
+ }
+
+ public Map<IGateSpec.Direction, Set<String>> getServiceClassNames() {
+ final Map<IGateSpec.Direction, Set<String>> out = new HashMap<>();
+
+ for (final ServiceClassNamesYaml scns : serviceClassNames) {
+ Set<String> names;
+ if (out.containsKey(scns.direction)) {
+ names = out.get(scns.direction);
+ } else {
+ names = new HashSet<>(scns.gateNames.size());
+ out.put(scns.direction, names);
+ }
+ names.addAll(scns.gateNames);
+ }
+ return out;
+ }
+
+ public Map<String, Boolean> getCmStatus() {
+ final Map<String, Boolean> out = new HashMap<>();
+
+ for (final CmStatusYaml cmStatus : cmStatuses) {
+ out.put(cmStatus.hostIp, cmStatus.status);
+ }
+
+ return out;
+ }
+
+
+ /**
+ * Class to hold the YAML gate configuration values
+ */
+ public static class ServiceClassNamesYaml {
+ @JsonProperty("direction")
+ private IGateSpec.Direction direction;
+
+ @JsonProperty("names")
+ private Set<String> gateNames;
+
+ public IGateSpec.Direction getDirection() {
+ return direction;
+ }
+
+ public Set<String> getGateNames() {
+ return Collections.unmodifiableSet(gateNames);
+ }
+ }
+
+
+ /**
+ * Class to hold the YAML Cable Modem configuration values
+ */
+ public static class CmStatusYaml {
+ @JsonProperty("host")
+ private String hostIp;
+
+ @JsonProperty("status")
+ private boolean status;
+ }
+}
package org.pcmm.rcd.impl;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import org.pcmm.gates.IGateSpec.Direction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*/
class PcmmCmtsConnection extends COPSPepConnection {
- private final static Logger logger = LoggerFactory.getLogger(COPSPepConnection.class);
-
- /**
- * The configured gates
- */
- private final Map<Direction, Set<String>> gateConfig;
+ private static final Logger logger = LoggerFactory.getLogger(COPSPepConnection.class);
- /**
- * The connected CMTSs and whether or not they are up
- */
- private final Map<String, Boolean> cmStatus;
+ private final CMTSConfig config;
/**
* Constructor
* @param clientType - the client-type
* @param sock - the socket connection
- * @param gateConfig - the configured gates
- * @param cmStatus - the configured CMs and whether or each is connected
+ * @param config - emulator configuration
*/
- public PcmmCmtsConnection(final short clientType, final Socket sock, final Map<Direction, Set<String>> gateConfig,
- final Map<String, Boolean> cmStatus) {
+ public PcmmCmtsConnection(final short clientType, final Socket sock, final CMTSConfig config) {
super(clientType, sock);
- this.gateConfig = Collections.unmodifiableMap(gateConfig);
- this.cmStatus = Collections.unmodifiableMap(cmStatus);
+ this.config = checkNotNull(config);
}
@Override
public COPSPepReqStateMan addRequestState(final COPSHandle clientHandle, final COPSPepDataProcess process)
throws COPSException {
final COPSPepReqStateMan manager = new CmtsPepReqStateMan(_clientType, clientHandle, (CmtsDataProcessor)process,
- _sock, gateConfig, cmStatus);
+ _sock, config);
if (_managerMap.get(clientHandle) != null)
throw new COPSPepException("Duplicate Handle, rejecting " + clientHandle);
}
grouping gate-operational-attributes {
- leaf gatePath {
- config false;
- type string;
- description "FQ Gate path app/subscriber/gate";
- mandatory true;
- }
- leaf ccapId {
- config false;
- type string;
- description "CCAP Identity";
- mandatory true;
- }
- leaf cops-state {
- config false;
- type string;
- description "Gate operational COPS state";
- mandatory true;
+ leaf gatePath {
+ config false;
+ type string;
+ description "FQ Gate path app/subscriber/gate";
+ mandatory true;
+ }
+ leaf ccapId {
+ config false;
+ type string;
+ description "CCAP Identity";
+ mandatory true;
+ }
+ leaf cops-gate-state {
+ config false;
+ type string;
+ description "Operational COPS Gate state";
+ mandatory true;
+ }
+ leaf cops-gate-time-info {
+ config false;
+ type string;
+ description "Operational COPS Gate time info";
+ mandatory true;
+ }
+ leaf cops-gate-usage-info {
+ config false;
+ type string;
+ description "Operational COPS gate usage info";
+ mandatory true;
}
leaf cops-gateId {
config false;
}
}
-}
+ //RPCs
+ rpc ccap-set-connection {
+ input {
+ leaf ccapId {
+ type instance-identifier;
+ ext:context-reference ccap-context;
+ }
+ container connection {
+ leaf connected {
+ type boolean;
+ description "COPS session state";
+ }
+// leaf idle-detect {
+// type uint8;
+// description "COPS connection idle timer";
+// }
+ }
+ }
+ output {
+ container ccap {
+ leaf ccapId {
+ type string;
+ }
+ container connection {
+ uses ccap-connection;
+ }
+ }
+ leaf response {
+ type string;
+ }
+ leaf timestamp {
+ type yang:date-and-time;
+ description "RPC timestamp";
+ }
+ }
+ }
+
+ rpc ccap-poll-connection {
+ input {
+ leaf ccapId {
+ type instance-identifier;
+ ext:context-reference ccap-context;
+ }
+ }
+ output {
+ container ccap {
+ leaf ccapId {
+ type string;
+ }
+ container connection {
+ uses ccap-connection;
+ }
+ }
+ leaf response {
+ type string;
+ }
+ leaf timestamp {
+ type yang:date-and-time;
+ description "RPC timestamp";
+ }
+ }
+ }
+ rpc qos-poll-gates {
+ input {
+ leaf appId {
+ type instance-identifier;
+ ext:context-reference app-context;
+ }
+ leaf subscriberId {
+ type string;
+ description "Subscriber Identity -- must be a CM or CPE IP address";
+ }
+ leaf gateId {
+ type string;
+ description "Qos Gate Identity";
+ }
+ }
+ output {
+ container gate {
+ uses gate-operational-attributes;
+ }
+ leaf response {
+ type string;
+ }
+ leaf timestamp {
+ type yang:date-and-time;
+ description "RPC timestamp";
+ }
+ }
+ }
+}
\ No newline at end of file
import org.pcmm.gates.impl.AMID;
import org.pcmm.gates.impl.DOCSISServiceClassNameTrafficProfile;
import org.pcmm.gates.impl.GateID;
+import org.pcmm.gates.impl.GateState;
+import org.pcmm.gates.impl.GateTimeInfo;
+import org.pcmm.gates.impl.GateUsageInfo;
import org.pcmm.gates.impl.PCMMError;
import org.pcmm.gates.impl.PCMMGateReq;
import org.pcmm.gates.impl.SubscriberID;
private ITrafficProfile trafficProfile = null;
private final List<IClassifier> classifiers = Lists.newArrayListWithExpectedSize(4);
private PCMMError error = null;
+ private GateState gateState = null;
+ private GateTimeInfo gateTimeInfo = null;
+ private GateUsageInfo gateUsageInfo = null;
public PCMMGateReq build() {
- return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers, gateID, error);
+ return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers,
+ gateID, error, gateState, gateTimeInfo, gateUsageInfo);
}
public void setAmId(final AmId qosAmId) {
final Short index = container.getClassifierId();
if (choice instanceof QosClassifierChoice) {
- addClassifier(((QosClassifierChoice) choice).getClassifier());
+ addClassifier(index, ((QosClassifierChoice) choice).getClassifier());
}
else if (choice instanceof ExtClassifierChoice) {
addExtClassifier(index, ((ExtClassifierChoice) choice).getExtClassifier());
}
}
- private void addClassifier(final Classifier qosClassifier) {
+ private void addClassifier(final Short index,final Classifier qosClassifier) {
// TODO - try and make these variables immutable
Protocol protocol = null;
byte tosOverwrite = 0;
short srcPort = (short) 0;
short dstPort = (short) 0;
byte priority = (byte) 64;
-
+ //byte priority = index.byteValue();
+
+
// Legacy classifier
if (qosClassifier.getProtocol() != null) {
protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
import org.pcmm.PCMMPdpAgent;
import org.pcmm.PCMMPdpDataProcess;
import org.pcmm.PCMMPdpMsgSender;
+import org.pcmm.gates.IGateState;
+import org.pcmm.gates.ITransactionID;
import org.pcmm.gates.impl.PCMMGateReq;
+import org.pcmm.gates.impl.TransactionID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.umu.cops.prpdp.COPSPdpException;
this.ccap = ccap;
ipAddr = ccap.getConnection().getIpAddress();
portNum = ccap.getConnection().getPort();
+
ccapClient = new CcapClient(ipAddr, portNum);
logger.info("Attempting to add CCAP with ID {} @ {}:{}", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(),
portNum.getValue());
}
}
- public class GateSetStatus {
+ public class GateSendStatus {
private boolean didSucceed = false;
private String message = "";
private String copsGateId = "";
+ private String copsGateState = "";
+ private String copsGateStateReason = "";
+ private String copsGateTimeInfo = "";
+ private String copsGateUsageInfo = "";
public boolean didSucceed() {
return didSucceed;
this.copsGateId = copsGateId;
}
+ public String getCopsGateState() {
+ return copsGateState;
+ }
+ void setCopsGateState(final String copsGateState) {
+ this.copsGateState = copsGateState;
+ }
+
+ public String getCopsGateStateReason() {
+ return copsGateStateReason;
+ }
+ void setCopsGateStateReason(final String copsGateStateReason) {
+ this.copsGateStateReason = copsGateStateReason;
+ }
+
+ public String getCopsGateTimeInfo() {
+ return copsGateTimeInfo;
+ }
+ void setCopsGateTimeInfo(final String copsGateTimeInfo) {
+ this.copsGateTimeInfo = copsGateTimeInfo;
+ }
+
+ public String getCopsGateUsageInfo() {
+ return copsGateUsageInfo;
+ }
+ void setCopsGateUsageInfo(final String copsGateUsageInfo) {
+ this.copsGateUsageInfo = copsGateUsageInfo;
+ }
}
- public GateSetStatus sendGateSet(final String gatePathStr, final InetAddress subId, final Gate qosGate,
+ public GateSendStatus sendGateSet(final String gatePathStr, final InetAddress subId, final Gate qosGate,
final ServiceFlowDirection scnDir) {
- GateSetStatus status = new GateSetStatus();
+ GateSendStatus status = new GateSendStatus();
logger.info("Sending gate to CCAP with ID - " + ccap.getCcapId());
} else {
logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
return false;
+ }
}
+
+ public Boolean getPcmmPdpSocket() {
+ try {
+ return ccapClient.pcmmPdp.getSocket().isClosed();
+ } catch (Exception e) {
+ logger.error("getPcmmPdpSocket: {} FAILED: {}", ccapClient, e.getMessage());
+ return true;
+ }
+ }
+
+ public Boolean getPcmmCcapClientIsConnected() {
+ try {
+ return ccapClient.isConnected;
+ } catch (Exception e) {
+ logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
+ return false;
+ }
+ }
+
+ public String getPcmmCcapClientConnectErrMsg() {
+ try {
+ return ccapClient.errMessage;
+ } catch (Exception e) {
+ logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
+ return e.getMessage();
+ }
+ }
+
+ //new gate-info method
+ public GateSendStatus sendGateInfo(final String gatePathStr) {
+
+ logger.info("sendGateInfo() - " + ccap);
+
+ GateSendStatus status = new GateSendStatus();
+
+ // recover the original gate request
+ final PCMMGateReq gateReq = gateRequests.get(gatePathStr);
+
+ // is the ccap socket open?
+ final Boolean socketIsClosed = getPcmmPdpSocket();
+
+ if ((gateReq != null) && (!socketIsClosed)) {
+ gateReq.setTransactionID(new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
+ ITransactionID.GateCommandType.GATE_INFO));
+
+ ccapClient.sendGateInfo(gateReq);
+ // and wait for the response to complete
+ try {
+ // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
+ // TODO - handle this synchronization.
+ synchronized (gateReq) {
+ logger.info("Waiting 5000ms for gate request to be updated");
+ gateReq.wait(5000);
+ logger.debug("Gate request error - " + gateReq.getError());
+ logger.debug("Gate request ID - " + gateReq.getGateID());
+ }
+ } catch (InterruptedException e) {
+ status.setDidSucceed(false);
+ status.setMessage(String.format("Gate-Info Request Timeout for %s", ccap.getCcapId()));
+ return status;
+ }
+ if (gateReq.getError() != null) {
+ status.setDidSucceed(false);
+ status.setMessage(
+ String.format("%s reports '%s'", ccap.getCcapId(), gateReq.getError().toString()));
+ logger.error("PCMMService: sendGateInfo(): returned error: {}", gateReq.getError().toString());
+ } else {
+ if (gateReq.getGateID() != null) {
+ status.setDidSucceed(true);
+ status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
+ //status.setMessage(String.format("200 OK - sendGateInfo for %s/%s returned GateId %08x",
+ // ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
+
+ final IGateState gateState = gateReq.getGateState();
+ status.setCopsGateState(gateState.getGateState().toString());
+ status.setCopsGateStateReason(gateState.getGateStateReason().toString());
+ status.setCopsGateTimeInfo(String.format("%d", gateReq.getGateTimeInfo().getGateTimeInfo()));
+ status.setCopsGateUsageInfo(String.format("%d", gateReq.getGateUsageInfo().getGateUsageInfo()));
+ logger.info(String.format("PCMMService: sendGateInfo(): returned GateId %08x: ",
+ gateReq.getGateID().getGateID()));
+ } else {
+ status.setDidSucceed(false);
+ status.setMessage(
+ String.format("404 Not Found - sendGateInfo for %s/%s no gateId returned", ccap.getCcapId(),
+ gatePathStr));
+
+ logger.info("PCMMService: sendGateInfo(): no gateId returned:");
+ }
+ return status;
+ }
+ } else {
+ status.setDidSucceed(false);
+ if (socketIsClosed) {
+ status.setMessage(String.format("%s: CCAP Cops Socket is closed",ccap.getCcapId()));
+ }
+ else {
+ status.setMessage( String.format("Attempt to get info of non-existent gate with path - " + gatePathStr));
+ }
+ return status;
+ }
+ return status;
+
}
/**
*/
public void connect() {
logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
+ errMessage = null;
try {
pcmmPdp.connect();
}
return true;
}
+
+ public Boolean sendGateInfo(final PCMMGateReq gateReq) {
+ logger.info("CcapClient: sendGateInfo(): {}:{} => {}", ipv4, port);
+ try {
+ pcmmSender.sendGateInfo(gateReq);
+ } catch (COPSPdpException e) {
+ logger.error("CcapClient: sendGateInfo(): {}:{} => {} FAILED: {}", ipv4, port,
+ e.getMessage());
+ }
+ return true;
+ }
}
}
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.packetcable.provider.validation.impl.CcapsValidatorProviderFactory;
import org.opendaylight.controller.packetcable.provider.validation.impl.QosValidatorProviderFactory;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.DateAndTime;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.AppContext;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapContext;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionInput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionOutput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionInput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionOutput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.Ccaps;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.PacketcableService;
import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.Qos;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesInput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesOutput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceClassName;
import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceFlowDirection;
import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.attributes.ConnectionBuilder;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.pcmm.rcd.IPCMMClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* <p>
* This class is responsible for processing messages received from ODL's restconf interface.
* TODO - Remove some of these state maps and move some of this into the PCMMService
+ * TODO Don't implement PacketcableService, move that into an inner class
*/
@ThreadSafe
-public class PacketcableProvider implements BindingAwareProvider, AutoCloseable {
+public class PacketcableProvider implements BindingAwareProvider, AutoCloseable, PacketcableService {
private static final Logger logger = LoggerFactory.getLogger(PacketcableProvider.class);
private DataBroker dataBroker;
private MdsalUtils mdsalUtils;
+ //Routed RPC Registration
+ private RoutedRpcRegistration<PacketcableService> rpcRegistration;
+
// Data change listeners/registrations
private final CcapsDataChangeListener ccapsDataChangeListener = new CcapsDataChangeListener();
private final QosDataChangeListener qosDataChangeListener = new QosDataChangeListener();
mdsalUtils = new MdsalUtils(dataBroker);
- ccapsDataChangeListenerRegistration = dataBroker
- .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, ccapsIID.child(Ccap.class),
+ ccapsDataChangeListenerRegistration =
+ dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, ccapsIID.child(Ccap.class),
ccapsDataChangeListener, DataBroker.DataChangeScope.SUBTREE);
- qosDataChangeListenerRegistration = dataBroker
- .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, PacketcableProvider.qosIID.child(Apps.class).child(App.class),
- qosDataChangeListener, DataBroker.DataChangeScope.SUBTREE);
+ qosDataChangeListenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ PacketcableProvider.qosIID.child(Apps.class).child(App.class), qosDataChangeListener,
+ DataBroker.DataChangeScope.SUBTREE);
+
+ rpcRegistration = session.addRoutedRpcImplementation(PacketcableService.class, this);
+ logger.info("onSessionInitiated().rpcRgistration: {}", rpcRegistration);
+
}
/**
// type match between iid and badData is done at start of loop
- @SuppressWarnings("unchecked")
- final InstanceIdentifier<Ccap> ccapIID = (InstanceIdentifier<Ccap>) iid;
+ @SuppressWarnings("unchecked") final InstanceIdentifier<Ccap> ccapIID = (InstanceIdentifier<Ccap>) iid;
writeTransaction.put(LogicalDatastoreType.OPERATIONAL, ccapIID, opperationalCcap);
- }
- else if (badData instanceof Gate) {
+ } else if (badData instanceof Gate) {
final Gate gate = (Gate) badData;
final Gate operationalGate =
- new GateBuilder()
- .setGateId(gate.getGateId())
- .setError(exception.getErrorMessages())
- .build();
+ new GateBuilder().setGateId(gate.getGateId()).setError(exception.getErrorMessages()).build();
- final Gates operationalGates = new GatesBuilder()
- .setGate(Collections.singletonList(operationalGate))
- .build();
+ final Gates operationalGates =
+ new GatesBuilder().setGate(Collections.singletonList(operationalGate)).build();
final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(iid.firstIdentifierOf(Subscriber.class));
- final Subscriber operationalSubscriber = new SubscriberBuilder()
- .setSubscriberId(subscriberKey.getSubscriberId())
- .setGates(operationalGates)
- .build();
+ final Subscriber operationalSubscriber =
+ new SubscriberBuilder().setSubscriberId(subscriberKey.getSubscriberId())
+ .setGates(operationalGates)
+ .build();
- final Subscribers operationalSubscribers = new SubscribersBuilder()
- .setSubscriber(Collections.singletonList(operationalSubscriber))
- .build();
+ final Subscribers operationalSubscribers =
+ new SubscribersBuilder().setSubscriber(Collections.singletonList(operationalSubscriber))
+ .build();
final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
final AppKey appKey = InstanceIdentifier.keyOf(appIID);
- final App operationalApp = new AppBuilder()
- .setAppId(appKey.getAppId())
- .setSubscribers(operationalSubscribers)
- .build();
+ final App operationalApp =
+ new AppBuilder().setAppId(appKey.getAppId()).setSubscribers(operationalSubscribers).build();
writeTransaction.put(LogicalDatastoreType.OPERATIONAL, appIID, operationalApp);
- }
- else {
+ } else {
// If you get here a developer forgot to add a type above
logger.error("Unexpected type requested for error saving: {}", badData);
throw new IllegalStateException("Unsupported type for error saving");
}
}
+
/**
* Removes Subscriber if all Gate instances are removed
*/
@Override
void postRemove(final InstanceIdentifier<App> appIID) {
+ //unregister app rpc path
+ logger.info("Un-Registering App Routed RPC Path...");
+ rpcRegistration.unregisterPath(AppContext.class, appIID);
executor.execute(new AppsCleaner(appIID));
}
}
/**
* Removes Apps if all App instances are removed.
*/
- private class AppsCleaner extends AbstractCleaner<Apps> {
+ private class AppsCleaner extends AbstractCleaner<Apps> {
public AppsCleaner(InstanceIdentifier<App> removedAppIID) {
super(removedAppIID, Apps.class, LogicalDatastoreType.OPERATIONAL);
/**
* Helper class to do the heavy lifting in removing object. Lets subclasses decide with
- * {@link #shouldClean(DataObject)}. <br>
- *
+ * {@link #shouldClean(DataObject)}. <br>
+ * <p>
* Subclasses can react after an instance is removed by overriding {@link #postRemove(InstanceIdentifier)}
- * @param <T> The type that will be removed
+ *
+ * @param <T>
+ * The type that will be removed
*/
- private abstract class AbstractCleaner <T extends DataObject> implements Runnable {
+ private abstract class AbstractCleaner<T extends DataObject> implements Runnable {
final InstanceIdentifier<?> removedIID;
final Class<T> tClass;
final LogicalDatastoreType datastoreType;
if (shouldClean(optional.get())) {
if (mdsalUtils.delete(datastoreType, tIID)) {
postRemove(tIID);
- }
- else {
+ } else {
removeFailed(tIID);
}
}
}
- }
- else {
- logger.error("Expected to find InstanceIdentifier<{}> but was not found: {}",
- tClass.getSimpleName(), removedIID);
+ } else {
+ logger.error("Expected to find InstanceIdentifier<{}> but was not found: {}", tClass.getSimpleName(),
+ removedIID);
}
}
/**
* If returns true the object will be removed from the datastore
- * @param object The object that might be removed.
+ *
+ * @param object
+ * The object that might be removed.
* @return true if it should be removed.
*/
abstract boolean shouldClean(final T object);
/**
* Called after an instance is removed.
- * @param tIID the InstanceIdentifier of the removed object
+ *
+ * @param tIID
+ * the InstanceIdentifier of the removed object
*/
void postRemove(InstanceIdentifier<T> tIID) {
updateCcapMaps(ccap);
logger.info("Created CCAP: {}/{} : {}", iid, ccap, message);
logger.info("Created CCAP: {} : {}", iid, message);
+
connectionBuilder.setConnected(true).setError(Collections.<String>emptyList());
} else {
logger.error("Create CCAP Failed: {} : {}", iid, message);
connectionBuilder.setConnected(false).setError(Collections.singletonList(message));
}
+ //register rpc
+ logger.info("Registering CCAP Routed RPC Path...");
+ rpcRegistration.registerPath(CcapContext.class, iid);
+
Optional<Ccap> optionalCcap = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
final CcapBuilder responseCcapBuilder;
final Ccap originalCcap = originalCcaps.get(entry.getKey());
//final Ccap updatedCcap = entry.getValue();
+ //register rpc
+ logger.info("Registering CCAP Routed RPC Path...");
+ rpcRegistration.registerPath(CcapContext.class, entry.getKey());
+
// restore the original data
updateQueue.add(entry.getKey());
mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, entry.getKey(), originalCcap);
final Ccap nukedCcap = originalCcaps.get(iid);
removeCcapFromAllMaps(nukedCcap);
+ //unregister ccap rpc path
+ logger.info("Un-Registering CCAP Routed RPC Path...");
+ rpcRegistration.unregisterPath(CcapContext.class, iid);
+
mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, iid);
// clean up ccaps level if it is now empty
final String newGatePathStr = makeGatePathString(gateIID);
+ // if a new app comes along add RPC registration
+ final InstanceIdentifier<App> appIID = gateIID.firstIdentifierOf(App.class);
+ // TBD verify if App ID exists first
+
+ //register appID RPC path
+ logger.info("Registering App Routed RPC Path...");
+ rpcRegistration.registerPath(AppContext.class, appIID);
+
final InstanceIdentifier<Subscriber> subscriberIID = gateIID.firstIdentifierOf(Subscriber.class);
final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
final InetAddress subscriberAddr = getInetAddress(subscriberKey.getSubscriberId());
final ServiceClassName scn = newGate.getTrafficProfile().getServiceClassName();
final ServiceFlowDirection scnDirection = findScnOnCcap(scn, ccap);
if (scnDirection == null) {
- final String msg = String.format("SCN %s not found on CCAP %s for %s",
- scn, ccap.getCcapId(), newGatePathStr);
+ final String msg =
+ String.format("SCN %s not found on CCAP %s for %s", scn, ccap.getCcapId(), newGatePathStr);
logger.error(msg);
saveGateError(gateIID, newGatePathStr, msg);
continue;
final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
if (pcmmService == null) {
- final String msg = String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s",
- ccap, subscriberKey.getSubscriberId());
+ final String msg =
+ String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s", ccap,
+ subscriberKey.getSubscriberId());
logger.error(msg);
saveGateError(gateIID, newGatePathStr, msg);
continue;
}
- PCMMService.GateSetStatus status = pcmmService.sendGateSet(newGatePathStr, subscriberAddr, newGate, scnDirection);
+ PCMMService.GateSendStatus status =
+ pcmmService.sendGateSet(newGatePathStr, subscriberAddr, newGate, scnDirection);
if (status.didSucceed()) {
gateMap.put(newGatePathStr, newGate);
gateCcapMap.put(newGatePathStr, ccap.getCcapId());
.setGatePath(newGatePathStr)
.setCcapId(ccap.getCcapId())
.setCopsGateId(status.getCopsGateId())
- .setCopsState(status.didSucceed() ? "success" : "failure");
+ .setCopsGateState("")
+ .setTimestamp(getNowTimeStamp())
+ .setCopsGateTimeInfo("")
+ .setCopsGateUsageInfo("")
+ .setTimestamp(getNowTimeStamp());
+
if (!status.didSucceed()) {
gateBuilder.setError(Collections.singletonList(status.getMessage()));
+ } else {
+ PCMMService.GateSendStatus infoStatus = pcmmService.sendGateInfo(newGatePathStr);
+
+ if (infoStatus.didSucceed()) {
+ gateBuilder.setCopsGateState(
+ infoStatus.getCopsGateState() + "/" + infoStatus.getCopsGateStateReason())
+ .setCopsGateTimeInfo(infoStatus.getCopsGateTimeInfo())
+ .setCopsGateUsageInfo(infoStatus.getCopsGateUsageInfo());
+ } else {
+ List<String> errors = new ArrayList<>(2);
+
+ // Keep GateSetErrors
+ if (gateBuilder.getError() != null) {
+ errors.addAll(gateBuilder.getError());
+ }
+
+ errors.add(infoStatus.getMessage());
+ gateBuilder.setError(errors);
+ }
+
}
Gate operationalGate = gateBuilder.build();
gateBuilder.setGateId(InstanceIdentifier.keyOf(gateIID).getGateId())
.setGatePath(gatePathStr)
.setCopsGateId("")
- .setCopsState("N/A");
+ .setCopsGateState("N/A");
- gateBuilder.setError(Collections.singletonList(error));
+ gateBuilder.setError(Collections.singletonList(error));
Gate operationalGate = gateBuilder.build();
final String gatePathStr = makeGatePathString(removedGateIID);
- if (gateMap.containsKey(gatePathStr)) {
- final Gate thisGate = gateMap.remove(gatePathStr);
- final String gateId = thisGate.getGateId();
- final String ccapId = gateCcapMap.remove(gatePathStr);
- final Ccap thisCcap = ccapMap.get(ccapId);
- final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
- if (service != null) {
- service.sendGateDelete(gatePathStr);
- logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr,
- thisGate);
- } else {
- logger.warn(
- "Unable to send to locate PCMMService to send gate delete message with CCAP - " + thisCcap);
- }
+ if (gateMap.containsKey(gatePathStr)) {
+ final Gate thisGate = gateMap.remove(gatePathStr);
+ final String gateId = thisGate.getGateId();
+ final String ccapId = gateCcapMap.remove(gatePathStr);
+ final Ccap thisCcap = ccapMap.get(ccapId);
+ final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
+ if (service != null) {
+ service.sendGateDelete(gatePathStr);
+ logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr,
+ thisGate);
+ } else {
+ logger.warn("Unable to send to locate PCMMService to send gate delete message with CCAP - "
+ + thisCcap);
}
+ }
}
final GateKey gateKey = InstanceIdentifier.keyOf(iid);
- return appKey.getAppId()
- + "/" + subscriberKey.getSubscriberId()
- + "/" + gateKey.getGateId();
+ return appKey.getAppId() + "/" + subscriberKey.getSubscriberId() + "/" + gateKey.getGateId();
+ }
+ }
+
+
+ @Override
+ public Future<RpcResult<CcapSetConnectionOutput>> ccapSetConnection(CcapSetConnectionInput input) {
+ // TODO refactor this method into smaller parts
+
+ InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
+ List<String> outputError = new ArrayList<String>();
+ String rpcResponse = null;
+ Boolean inputIsConnected = input.getConnection().isConnected();
+ Boolean effectiveIsConnected = null;
+ String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
+ PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+
+ if (!inputIsConnected) {
+ // set connected false
+ if (pcmmService.getPcmmPdpSocket()) {
+ outputError.add(ccapId + ": CCAP COPS socket is already closed");
+ effectiveIsConnected = false;
+ } else {
+ //if (!pcmmService.getPcmmCcapClientIsConnected()) {
+ outputError.add(ccapId + ": CCAP client is disconnected with error: "
+ + pcmmService.getPcmmCcapClientConnectErrMsg());
+ //}
+ pcmmService.ccapClient.disconnect();
+ effectiveIsConnected = false;
+ }
+ } else {
+ // set connected true
+ if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+ outputError.add(ccapId + ": CCAP COPS socket is already open");
+ outputError.add(ccapId + ": CCAP client is connected");
+ effectiveIsConnected = true;
+ } else {
+ if (pcmmService.getPcmmCcapClientIsConnected()) {
+ pcmmService.ccapClient.disconnect();
+ }
+ pcmmService.ccapClient.connect();
+ if (pcmmService.getPcmmCcapClientIsConnected()) {
+ effectiveIsConnected = true;
+ outputError.add(ccapId + ": CCAP client is connected");
+ } else {
+ effectiveIsConnected = false;
+ outputError.add(ccapId + ": CCAP client is disconnected with error: "
+ + pcmmService.getPcmmCcapClientConnectErrMsg());
+ }
+ }
+ }
+
+ DateAndTime connectionDateAndTime = getNowTimeStamp();
+ org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.ccap.ConnectionBuilder
+ connectionRpcOutput =
+ new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.ccap.ConnectionBuilder()
+ .setConnected(effectiveIsConnected)
+ .setError(outputError)
+ .setTimestamp(connectionDateAndTime);
+
+ org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.CcapBuilder ccapRpcOutput =
+ new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.CcapBuilder().setCcapId(
+ ccapId).setConnection(connectionRpcOutput.build());
+
+
+ ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
+ .setError(outputError)
+ .setTimestamp(connectionDateAndTime);
+
+ CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
+
+
+ mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
+
+
+ DateAndTime rpcDateAndTime = getNowTimeStamp();
+ rpcResponse = ccapId + ": CCAP set complete";
+ CcapSetConnectionOutputBuilder outputBuilder =
+ new CcapSetConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
+ .setResponse(rpcResponse)
+ .setTimestamp(rpcDateAndTime);
+
+ return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
+ }
+
+
+
+ @Override
+ public Future<RpcResult<CcapPollConnectionOutput>> ccapPollConnection(CcapPollConnectionInput input) {
+ // TODO refactor this method into smaller parts
+
+ InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
+ List<String> outputError = new ArrayList<String>();
+
+ String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
+ PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+ Boolean effectiveIsConnected = true;
+ String response = null;
+ org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder
+ connectionRpcOutput =
+ new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder();
+
+ if (pcmmService != null) {
+ if (pcmmService.getPcmmPdpSocket()) {
+ outputError.add(ccapId + ": CCAP Cops socket is closed");
+ if (!pcmmService.getPcmmCcapClientIsConnected()) {
+ outputError.add(ccapId + ": CCAP client is disconnected with error: "
+ + pcmmService.getPcmmCcapClientConnectErrMsg());
+ }
+ effectiveIsConnected = false;
+ } else {
+ //outputError.add(String.format(ccapId+": CCAP Cops socket is open"));
+ if (!pcmmService.getPcmmCcapClientIsConnected()) {
+ outputError.add(ccapId + ": CCAP client is disconnected with error: "
+ + pcmmService.getPcmmCcapClientConnectErrMsg());
+ effectiveIsConnected = false;
+ } else {
+ outputError.add(ccapId + ": CCAP client is connected");
+ }
+ }
+ DateAndTime connectionDateAndTime = getNowTimeStamp();
+
+
+ ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
+ .setError(outputError)
+ .setTimestamp(connectionDateAndTime);
+
+ CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
+
+ connectionRpcOutput =
+ new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder()
+ .setConnected(effectiveIsConnected)
+ .setError(outputError)
+ .setTimestamp(connectionDateAndTime);
+
+ mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
+ response = ccapId + ": CCAP poll complete";
+ } else {
+ //pcmmService is null, do not poll
+ response = ccapId + ": CCAP connection null; no poll performed";
+ }
+
+ DateAndTime rpcDateAndTime = getNowTimeStamp();
+
+ org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.CcapBuilder ccapRpcOutput =
+ new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.CcapBuilder().setCcapId(
+ ccapId).setConnection(connectionRpcOutput.build());
+
+ CcapPollConnectionOutputBuilder outputBuilder =
+ new CcapPollConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
+ .setResponse(response)
+ .setTimestamp(rpcDateAndTime);
+
+ return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
+ }
+
+
+
+ private App readAppFromOperationalDatastore(InstanceIdentifier<App> appIid) {
+ Optional<App> optionalApp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, appIid);
+ AppBuilder thisAppBuilder = new AppBuilder(optionalApp.get());
+ App thisApp = thisAppBuilder.build();
+ logger.info("readAppFromConfigDatastore() retrived App: " + thisApp.getAppId());
+ return thisApp;
+ }
+
+ private Gate readGateFromOperationalDatastore(InstanceIdentifier<Gate> gateIid) {
+ Optional<Gate> optionalGate = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, gateIid);
+ if (optionalGate.isPresent()) {
+ GateBuilder gateBuilder = new GateBuilder(optionalGate.get());
+ Gate thisGate = gateBuilder.build();
+ return thisGate;
+ } else {
+ return null;
+ }
+ }
+
+ private Subscriber readSubscriberFromOperationalDatastore(InstanceIdentifier<Subscriber> subscriberIid) {
+ Optional<Subscriber> optionalSubscriber = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, subscriberIid);
+ if (optionalSubscriber.isPresent()) {
+ SubscriberBuilder subscriberBuilder = new SubscriberBuilder(optionalSubscriber.get());
+ Subscriber thisSubscriber = subscriberBuilder.build();
+ return thisSubscriber;
+ } else {
+ return null;
}
}
+
+
+ @Override
+ public Future<RpcResult<QosPollGatesOutput>> qosPollGates(QosPollGatesInput input) {
+ // TODO refactor this method into smaller parts
+
+ InstanceIdentifier<App> appIid = (InstanceIdentifier<App>) input.getAppId();
+ //logger.info("qospollgates appIid : "+appIid.toString());
+ App app = readAppFromOperationalDatastore(appIid);
+ //logger.info("qospollgates app : "+app.toString());
+ AppKey appKey = InstanceIdentifier.keyOf(appIid);
+ String inputSubscriberId = input.getSubscriberId();
+ String inputGateId = input.getGateId();
+ List<String> gateOutputError = Collections.emptyList();
+ String subscriberId = null;
+ String gateId = null;
+ String ccapId = null;
+ String gatePathStr = null;
+ String opsCopsGateId = null;
+ Gate opsGate = null;
+
+ String rpcResponse = null;
+
+ org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.qos.poll.gates.output.GateBuilder gateOutputBuilder =
+ new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.qos.poll.gates.output.GateBuilder();
+
+ GateBuilder gateBuilder = new GateBuilder();
+
+ if (inputSubscriberId != null) {
+ if (inputGateId != null) {
+ //Subscriber Id and Gate Id provided, only one gate to be poolled
+
+ //generate the gateiid
+ InstanceIdentifier<Gate> gateIid = appIid.builder()
+ .child(Subscribers.class)
+ .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
+ .child(Gates.class)
+ .child(Gate.class, new GateKey(inputGateId))
+ .build();
+
+
+ opsGate = readGateFromOperationalDatastore(gateIid);
+
+ //does the gate exists in the Operational DS?
+ if (opsGate == null) {
+ gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
+ rpcResponse = gatePathStr + ": gate does not exist in the system; gate poll not performed";
+ } else {
+ opsCopsGateId = opsGate.getCopsGateId();
+ gatePathStr = opsGate.getGatePath();
+
+ if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
+ ccapId = findCcapForSubscriberId(getInetAddress(inputSubscriberId)).getCcapId();
+ PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+ //is the CCAP socket open?
+ if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+ PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
+ DateAndTime gateDateAndTime = getNowTimeStamp();
+ //logger.info("qospollgates Gate Status : GateID/"+status.getCopsGateId());
+ //logger.info("qospollgates Gate Status : Message/"+status.getMessage());
+ //logger.info("qospollgates Gate Status : DidSucceed/"+status.didSucceed());
+ gateOutputError = Collections.singletonList(status.getMessage());
+
+ gateOutputBuilder.setGatePath(gatePathStr)
+ .setCcapId(ccapId)
+ .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+ .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+ .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+ .setCopsGateId(status.getCopsGateId())
+ .setError(gateOutputError)
+ .setTimestamp(gateDateAndTime);
+
+ gateBuilder.setGateId(inputGateId)
+ .setGatePath(gatePathStr)
+ .setCcapId(ccapId)
+ .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+ .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+ .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+ .setCopsGateId(status.getCopsGateId())
+ .setError(gateOutputError)
+ .setTimestamp(gateDateAndTime);
+
+ mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
+ rpcResponse = gatePathStr + ": gate poll complete";
+ } else {
+ rpcResponse =
+ ccapId + ": CCAP socket is down or client disconnected; gate poll not performed";
+ }
+ } else {
+ rpcResponse = gatePathStr + ": gate not active; gate poll not performed";
+ }
+ }
+ } else {
+ //inputGateId is null; pool all gates for the subscriber if the sub exists
+
+ //generate active subIid
+ InstanceIdentifier<Subscriber> subIid = appIid.builder()
+ .child(Subscribers.class)
+ .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
+ .build();
+ //does the subscriber provided exists in the Operational Datastore?
+ Subscriber sub = readSubscriberFromOperationalDatastore(subIid);
+ if (sub != null) {
+ //If Subscriber exsits poll all gates for the subscriber
+ subscriberId = sub.getSubscriberId();
+ List<Gate> gateList = sub.getGates().getGate();
+ for (Gate gate : gateList) {
+ //generate active gateIid
+ gateId = gate.getGateId();
+ InstanceIdentifier<Gate> gateIid =
+ subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
+
+ opsGate = readGateFromOperationalDatastore(gateIid);
+ opsCopsGateId = opsGate.getCopsGateId();
+ //generate active gatePathStr
+ gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
+
+ if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
+ ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
+ PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+ //is the CCAP socket open?
+ if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+ PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
+ DateAndTime gateDateAndTime = getNowTimeStamp();
+
+ gateBuilder.setGateId(gateId)
+ .setGatePath(gatePathStr)
+ .setCcapId(ccapId)
+ .setCopsGateState(
+ status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+ .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+ .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+ .setCopsGateId(status.getCopsGateId())
+ .setError(gateOutputError)
+ .setTimestamp(gateDateAndTime);
+
+ mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
+ } else {
+ logger.info(
+ "qospollgates: {}: CCAP Cops socket is down or client disconnected; gate poll not performed",
+ ccapId);
+ }
+ } else {
+ //TODO define what happens if a gate is not active.. is nothing ok?
+ logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
+ }
+ } //for
+ rpcResponse = inputSubscriberId + "/: subscriber subtree poll in progress";
+ } else {
+ rpcResponse =
+ inputSubscriberId + "/: subscriber is not defined in the system, gate poll not performed";
+ }
+ }
+ } //inputSubId if
+ else {
+ // inputSubId is null
+ if (inputGateId != null) {
+ gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
+ rpcResponse = gatePathStr + ": Subscriber ID not provided; gate poll not performed";
+ } else {
+ //poll all gates for the appId
+
+ Subscribers subs = app.getSubscribers();
+
+ logger.info("qospollgates subscribers: " + subs.toString());
+
+ List<Subscriber> subList = subs.getSubscriber();
+ logger.info("qospollgates subList: " + subList.toString());
+ for (Subscriber sub : subList) {
+
+ //generate active subIid
+ subscriberId = sub.getSubscriberId();
+ InstanceIdentifier<Subscriber> subIid = appIid.builder()
+ .child(Subscribers.class)
+ .child(Subscriber.class, new SubscriberKey(subscriberId))
+ .build();
+
+ List<Gate> gateList = sub.getGates().getGate();
+ for (Gate gate : gateList) {
+ //logger.info("qospollgates active gate: "+gate);
+
+ //generate active gateIid
+ gateId = gate.getGateId();
+ InstanceIdentifier<Gate> gateIid =
+ subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
+
+ opsGate = readGateFromOperationalDatastore(gateIid);
+ opsCopsGateId = opsGate.getCopsGateId();
+ //generate active gatePathStr
+ gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
+ if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
+ ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
+ PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+ //is the CCAP socket open?
+ if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+ PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
+ DateAndTime gateDateAndTime = getNowTimeStamp();
+ gateOutputError = Collections.singletonList(status.getMessage());
+
+
+ gateBuilder.setGateId(gateId)
+ .setGatePath(gatePathStr)
+ .setCcapId(ccapId)
+ .setCopsGateState(
+ status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+ .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+ .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+ .setCopsGateId(status.getCopsGateId())
+ .setError(gateOutputError)
+ .setTimestamp(gateDateAndTime);
+
+ mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
+ } else {
+ logger.info(
+ "qospollgates: {}: CCAP socket is down or client disconnected; gate poll not performed",
+ ccapId);
+ }
+ } else {
+ //TODO define what happens if a gate is not active.. is nothing ok
+ logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
+ }
+ }
+ }
+ rpcResponse = appKey.getAppId() + "/: gate subtree poll in progress";
+ }
+ }
+
+ DateAndTime rpcDateAndTime = getNowTimeStamp();
+
+ QosPollGatesOutputBuilder outputBuilder = new QosPollGatesOutputBuilder().setTimestamp(rpcDateAndTime)
+ .setResponse(rpcResponse)
+ .setGate(gateOutputBuilder.build());
+ return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
+ }
+
+ private DateAndTime getNowTimeStamp() {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
+ return new DateAndTime(dateFormat.format(new Date()));
+ }
}
package org.opendaylight.controller.packetcable.provider;
import static junit.framework.TestCase.assertEquals;
+
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.traffic.profile.TrafficProfile;
import org.pcmm.PCMMPdpAgent;
-import org.pcmm.gates.IGateSpec.Direction;
import org.pcmm.gates.IPCMMGate;
import org.pcmm.rcd.IPCMMClient;
import org.pcmm.rcd.impl.CMTS;
+import org.pcmm.rcd.impl.CMTSConfig;
import org.umu.cops.stack.COPSClientSI;
import org.umu.cops.stack.COPSContext;
import org.umu.cops.stack.COPSContext.RType;
public void setup() throws IOException {
srcAddr = new Ipv4Address("10.10.10.0");
dstAddr = new Ipv4Address("10.32.99.99");
+ invalidCmAddrInet = InetAddress.getByAddress(new byte[] {99, 99, 99, 99});
if (realCmts) {
cmAddrInet = InetAddress.getByAddress(new byte[] {10, 32, 110, (byte)172});
- invalidCmAddrInet = InetAddress.getByAddress(new byte[] {99, 99, 99, 99});
+
// Use me when testing against a CMTS or emulator not running in the same JVM
cmtsAddr = new Ipv4Address("10.32.10.3");
ccap = makeCcapObj(PCMMPdpAgent.WELL_KNOWN_PDP_PORT, cmtsAddr, ccapId);
} else {
cmAddrInet = InetAddress.getByAddress(new byte[] {10, 32, 110, (byte)180});
- invalidCmAddrInet = InetAddress.getByAddress(new byte[] {99, 99, 99, 99});
// Use me for automated testing and the CMTS emulator running in the same JVM
cmtsAddr = new Ipv4Address("127.0.0.1");
- final Set<String> upGate = new HashSet<>();
- upGate.add("extrm_up");
- final Set<String> dnGate = new HashSet<>();
- dnGate.add("extrm_dn");
- final Map<Direction, Set<String>> gates = new HashMap<>();
- gates.put(Direction.UPSTREAM, upGate);
- gates.put(Direction.DOWNSTREAM, dnGate);
+ final Set<String> upSCN = new HashSet<>();
+ upSCN.add("extrm_up");
+ final Set<String> dnSCN = new HashSet<>();
+ dnSCN.add("extrm_dn");
final Map<String, Boolean> cmStatus = new HashMap<>();
cmStatus.put(cmAddrInet.getHostAddress(), true);
cmStatus.put(invalidCmAddrInet.getHostAddress(), false);
- icmts = new CMTS(gates, cmStatus);
+
+ CMTSConfig config = new CMTSConfig(0, (short)4, upSCN, dnSCN, cmStatus);
+
+ icmts = new CMTS(config);
icmts.startServer();
ccap = makeCcapObj(icmts.getPort(), cmtsAddr, ccapId);
public void testAddAndRemoveInvalidCmAddrUpGate() throws Exception {
// TODO - fix cmts emulator
final String expectedMsgStart = "404 Not Found - sendGateSet for " + ccapId + '/' + gatePath
- + " returned error - Error Code: 13 Error Subcode : 0 Invalid SubscriberID";
+ + " returned error - Error Code: 13 Subcode: 0 Invalid SubscriberID";
addInvalidGate(service, "extrm_up", srcAddr, dstAddr, ServiceFlowDirection.Us, invalidCmAddrInet, gatePath,
expectedMsgStart);
}
@Test
public void testAddInvalidScnUpGate() throws Exception {
final String expectedMsgStart = "404 Not Found - sendGateSet for " + ccapId + '/' + gatePath
- + " returned error - Error Code: 11 Error Subcode : 0 Undefined Service Class Name";
+ + " returned error - Error Code: 11 Subcode: 0 Undefined Service Class Name";
addInvalidGate(service, "extrm_up_invalid", srcAddr, dstAddr, ServiceFlowDirection.Us, cmAddrInet, gatePath,
expectedMsgStart);
}
@Test
public void testAddInvalidScnDownGate() throws Exception {
final String expectedMsgStart = "404 Not Found - sendGateSet for " + ccapId + '/' + gatePath
- + " returned error - Error Code: 11 Error Subcode : 0 Undefined Service Class Name";
+ + " returned error - Error Code: 11 Subcode: 0 Undefined Service Class Name";
addInvalidGate(service, "extrm_dn_invalid", srcAddr, dstAddr, ServiceFlowDirection.Ds, cmAddrInet, gatePath,
expectedMsgStart);
}
// Assert.assertNotNull(gateSetMsg);
// Assert.assertTrue(gateSetMsg, gateSetMsg.startsWith(expGateSetMsgStart));
- // TODO update this method for the new GateSetStatus object
- PCMMService.GateSetStatus status = service.sendGateSet(gatePath, cmAddrInet, gate, direction);
+ // TODO update this method for the new GateSendStatus object
+ PCMMService.GateSendStatus status = service.sendGateSet(gatePath, cmAddrInet, gate, direction);
Assert.assertNotNull(status);
- Assert.assertTrue(status.getMessage().startsWith(expGateSetMsgStart));
+ assertThat(status.getMessage(), startsWith(expGateSetMsgStart));
+
// TODO - add validation to the PCMMGateReq contained within the map
if (status.didSucceed()) {