2 * Copyright (c) 2015 CableLabs and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.packetcable.provider;
10 import com.google.common.collect.Maps;
11 import java.net.InetAddress;
13 import javax.annotation.concurrent.ThreadSafe;
14 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
16 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161128.ServiceClassName;
17 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161128.ServiceFlowDirection;
18 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161128.ccaps.Ccap;
19 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161128.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
20 import org.pcmm.PCMMPdpAgent;
21 import org.pcmm.PCMMPdpDataProcess;
22 import org.pcmm.PCMMPdpMsgSender;
23 import org.pcmm.gates.IGateState;
24 import org.pcmm.gates.ITransactionID;
25 import org.pcmm.gates.impl.PCMMGateReq;
26 import org.pcmm.gates.impl.TransactionID;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.umu.cops.prpdp.COPSPdpException;
30 import org.umu.cops.stack.COPSError;
31 import org.umu.cops.stack.COPSError.ErrorTypes;
34 * Class responsible for managing the gates for a single CCAP.
37 public class PCMMService {
38 private final Logger logger = LoggerFactory.getLogger(PCMMService.class);
40 private final Ccap ccap;
41 private final IpAddress ipAddr;
42 private final PortNumber portNum;
43 protected final CcapClient ccapClient;
44 protected Map<String, PCMMGateReq> gateRequests = Maps.newConcurrentMap();
46 private final short clientType;
48 public PCMMService(final short clientType, final Ccap ccap) {
49 this.clientType = clientType;
51 ipAddr = ccap.getConnection().getIpAddress();
52 portNum = ccap.getConnection().getPort();
54 ccapClient = new CcapClient(ipAddr, portNum);
55 logger.info("Attempting to add CCAP with ID {} @ {}:{}", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(),
59 public void disconect() {
60 ccapClient.disconnect();
63 // TODO - try and change the return to something other than a String to be parsed to determine success
64 public String addCcap() {
66 if (ccapClient.isConnected) {
67 logger.info("Connected to CCAP with ID - " + ccap.getCcapId());
69 .format("200 OK - CCAP %s connected @ %s:%d", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(),
72 return String.format("404 Not Found - CCAP %s failed to connect @ %s:%d - %s", ccap.getCcapId(),
73 ipAddr.getIpv4Address().getValue(), portNum.getValue(), ccapClient.errMessage);
77 public class GateSendStatus {
78 private boolean didSucceed = false;
79 private String message = "";
80 private String copsGateId = "";
81 private String copsGateState = "";
82 private String copsGateStateReason = "";
83 private String copsGateTimeInfo = "";
84 private String copsGateUsageInfo = "";
86 public boolean didSucceed() {
90 void setDidSucceed(final boolean didSucceed) {
91 this.didSucceed = didSucceed;
94 public String getMessage() {
98 void setMessage(final String message) {
99 this.message = message;
102 public String getCopsGateId() {
106 void setCopsGateId(final String copsGateId) {
107 this.copsGateId = copsGateId;
110 public String getCopsGateState() {
111 return copsGateState;
113 void setCopsGateState(final String copsGateState) {
114 this.copsGateState = copsGateState;
117 public String getCopsGateStateReason() {
118 return copsGateStateReason;
120 void setCopsGateStateReason(final String copsGateStateReason) {
121 this.copsGateStateReason = copsGateStateReason;
124 public String getCopsGateTimeInfo() {
125 return copsGateTimeInfo;
127 void setCopsGateTimeInfo(final String copsGateTimeInfo) {
128 this.copsGateTimeInfo = copsGateTimeInfo;
131 public String getCopsGateUsageInfo() {
132 return copsGateUsageInfo;
134 void setCopsGateUsageInfo(final String copsGateUsageInfo) {
135 this.copsGateUsageInfo = copsGateUsageInfo;
139 public GateSendStatus sendGateSet(final String gatePathStr, final InetAddress subId, final Gate qosGate) {
141 GateSendStatus status = new GateSendStatus();
143 logger.info("Sending gate to CCAP with ID - " + ccap.getCcapId());
145 // assemble the gate request for this subId
146 final PCMMGateReqBuilder gateBuilder = new PCMMGateReqBuilder();
147 gateBuilder.setAmId(ccap.getAmId());
148 gateBuilder.setSubscriberId(subId);
149 gateBuilder.setGateSpec(qosGate.getGateSpec(), null);
150 gateBuilder.setTrafficProfile(qosGate.getTrafficProfile());
151 gateBuilder.setClassifiers(qosGate.getClassifiers().getClassifierContainer());
153 // assemble the final gate request
154 final PCMMGateReq gateReq = gateBuilder.build();
156 if (gateRequests.get(gatePathStr) == null) {
158 gateRequests.put(gatePathStr, gateReq);
159 // and send it to the CCAP
160 ccapClient.sendGateSet(gateReq);
161 // and wait for the COPS response to complete processing gate request
163 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
164 // TODO - handle this synchronization.
165 // TODO - if not changing this, may want to make this timeout configurable
166 synchronized (gateReq) {
167 logger.info("Waiting 5000ms for gate request to be updated");
169 logger.debug("Gate request error - " + gateReq.getError());
170 logger.debug("Gate request ID - " + gateReq.getGateID());
172 } catch (Exception e) {
174 "PCMMService: sendGateSet(): gate response timeout exceeded for " + gatePathStr + '/' + gateReq,
176 status.setDidSucceed(false);
177 status.setMessage(String.format("408 Request Timeout - gate response timeout exceeded for %s/%s", ccap.getCcapId(),
183 if (gateReq.getError() != null) {
184 gateRequests.remove(gatePathStr);
185 status.setDidSucceed(false);
187 String.format("404 Not Found - sendGateSet for %s/%s returned error - %s", ccap.getCcapId(),
188 gatePathStr, gateReq.getError().toString()));
190 logger.error("PCMMService: sendGateSet(): returned error: {}", gateReq.getError().toString());
192 if (gateReq.getGateID() != null) {
193 status.setDidSucceed(true);
194 status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
195 status.setMessage(String.format("200 OK - sendGateSet for %s/%s returned GateId %08x",
196 ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
197 logger.info(String.format("PCMMService: sendGateSet(): returned GateId %08x: ",
198 gateReq.getGateID().getGateID()));
200 status.setDidSucceed(false);
202 String.format("404 Not Found - sendGateSet for %s/%s no gateId returned", ccap.getCcapId(),
205 logger.info("PCMMService: sendGateSet(): no gateId returned:");
209 logger.info("PCMMService: sendGateSet(): no gateId returned:");
210 status.setMessage(String.format("404 Not Found - sendGateSet for %s/%s already exists", ccap.getCcapId(), gatePathStr));
216 public Boolean sendGateDelete(final String gatePathStr) {
217 logger.info("sendGateDelete() - " + ccap);
218 // recover the original gate request
219 final PCMMGateReq gateReq = gateRequests.remove(gatePathStr);
220 if (gateReq != null) {
221 ccapClient.sendGateDelete(gateReq);
222 // and wait for the response to complete
224 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
225 // TODO - handle this synchronization.
226 synchronized (gateReq) {
229 } catch (InterruptedException e) {
230 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}", gatePathStr,
233 if (gateReq.getError() != null) {
234 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
237 if (gateReq.getGateID() != null) {
238 logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ",
239 gateReq.getGateID().getGateID()));
241 logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
246 logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
251 public Boolean getPcmmPdpSocket() {
253 return ccapClient.pcmmPdp.getSocket().isClosed();
254 } catch (Exception e) {
255 logger.error("getPcmmPdpSocket: {} FAILED: {}", ccapClient, e.getMessage());
260 public Boolean getPcmmCcapClientIsConnected() {
262 return ccapClient.isConnected;
263 } catch (Exception e) {
264 logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
269 public String getPcmmCcapClientConnectErrMsg() {
271 return ccapClient.errMessage;
272 } catch (Exception e) {
273 logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
274 return e.getMessage();
278 //new gate-info method
279 public GateSendStatus sendGateInfo(final String gatePathStr) {
281 logger.info("sendGateInfo() - " + ccap);
283 GateSendStatus status = new GateSendStatus();
285 // recover the original gate request
286 final PCMMGateReq gateReq = gateRequests.get(gatePathStr);
288 // is the ccap socket open?
289 final Boolean socketIsClosed = getPcmmPdpSocket();
291 if ((gateReq != null) && (!socketIsClosed)) {
292 gateReq.setTransactionID(new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
293 ITransactionID.GateCommandType.GATE_INFO));
295 ccapClient.sendGateInfo(gateReq);
296 // and wait for the response to complete
298 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
299 // TODO - handle this synchronization.
300 synchronized (gateReq) {
301 logger.info("Waiting 5000ms for gate request to be updated");
303 logger.debug("Gate request error - " + gateReq.getError());
304 logger.debug("Gate request ID - " + gateReq.getGateID());
306 } catch (InterruptedException e) {
307 status.setDidSucceed(false);
308 status.setMessage(String.format("Gate-Info Request Timeout for %s", ccap.getCcapId()));
311 if (gateReq.getError() != null) {
312 status.setDidSucceed(false);
314 String.format("%s reports '%s'", ccap.getCcapId(), gateReq.getError().toString()));
315 logger.error("PCMMService: sendGateInfo(): returned error: {}", gateReq.getError().toString());
317 if (gateReq.getGateID() != null) {
318 status.setDidSucceed(true);
319 status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
320 //status.setMessage(String.format("200 OK - sendGateInfo for %s/%s returned GateId %08x",
321 // ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
323 final IGateState gateState = gateReq.getGateState();
324 status.setCopsGateState(gateState.getGateState().toString());
325 status.setCopsGateStateReason(gateState.getGateStateReason().toString());
326 status.setCopsGateTimeInfo(String.format("%d", gateReq.getGateTimeInfo().getGateTimeInfo()));
327 status.setCopsGateUsageInfo(String.format("%d", gateReq.getGateUsageInfo().getGateUsageInfo()));
328 logger.info(String.format("PCMMService: sendGateInfo(): returned GateId %08x: ",
329 gateReq.getGateID().getGateID()));
331 status.setDidSucceed(false);
333 String.format("404 Not Found - sendGateInfo for %s/%s no gateId returned", ccap.getCcapId(),
336 logger.info("PCMMService: sendGateInfo(): no gateId returned:");
341 status.setDidSucceed(false);
342 if (socketIsClosed) {
343 status.setMessage(String.format("%s: CCAP Cops Socket is closed",ccap.getCcapId()));
346 status.setMessage( String.format("Attempt to get info of non-existent gate with path - " + gatePathStr));
355 * Used to interface with a CCAP (including CMTSs)
357 protected class CcapClient {
358 public final PCMMPdpDataProcess pcmmProcess;
359 public final PCMMPdpAgent pcmmPdp;
361 private final String ipv4;
362 private final Integer port;
364 // Needs to be initialized in connect() method else would be final
365 protected transient PCMMPdpMsgSender pcmmSender;
367 private transient Boolean isConnected = false;
368 private transient String errMessage = null;
374 * - the IP of the CCAP to manage
376 * - the port number of the CCAP to manage
378 public CcapClient(final IpAddress ccapIp, final PortNumber portNum) {
379 ipv4 = ccapIp.getIpv4Address().getValue();
380 if (portNum != null) {
381 port = portNum.getValue();
383 port = PCMMPdpAgent.WELL_KNOWN_PDP_PORT;
385 // TODO FIXME - if this object is not null, gate processing will not work correctly
386 // TODO see - PCMMPdpReqStateMan#processReport() where the report type is success and the process is null
387 // pcmmProcess = new PCMMPdpDataProcess();
389 pcmmPdp = new PCMMPdpAgent(ipv4, port, clientType, pcmmProcess);
393 * Starts the connection to the CCAP
395 public void connect() {
396 logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
401 // Cannot instantiate until after pcmmPdp.connect() is called as this is where the client handle is created
402 pcmmSender = new PCMMPdpMsgSender(clientType, pcmmPdp.getClientHandle(), pcmmPdp.getSocket());
405 } catch (Exception e) {
407 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
408 errMessage = e.getMessage();
412 public void disconnect() {
413 logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
414 pcmmPdp.disconnect(new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
418 // TODO - consider returning a new PCMMGateReq object or a future here instead of setting the ID on the old
419 // TODO - request by reference which makes the code more convoluted thus making issues more difficult to track down.
420 public Boolean sendGateSet(final PCMMGateReq gateReq) {
421 logger.info("CcapClient: sendGateSet(): {}:{} => {}", ipv4, port, gateReq);
423 pcmmSender.sendGateSet(gateReq);
425 // TODO - determine if this is the correct place to perform this operation as this currently is the
426 // TODO - place where the gate ID can be set on the gateReq object
427 // pcmmSender.handleGateReport(pcmmPdp.getSocket());
428 } catch (COPSPdpException e) {
429 logger.error("CcapClient: sendGateSet(): {}:{} => {} FAILED:", ipv4, port, gateReq, e);
431 // and save it back to the gateRequest object for gate delete later
432 gateReq.setGateID(pcmmSender.getGateID());
434 // TODO - determine why this method is always returning true???
438 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
439 logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
441 pcmmSender.sendGateDelete(gateReq);
442 } catch (COPSPdpException e) {
443 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq,
449 public Boolean sendGateInfo(final PCMMGateReq gateReq) {
450 logger.info("CcapClient: sendGateInfo(): {}:{} => {}", ipv4, port);
452 pcmmSender.sendGateInfo(gateReq);
453 } catch (COPSPdpException e) {
454 logger.error("CcapClient: sendGateInfo(): {}:{} => {} FAILED: {}", ipv4, port,