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.rev100924.IpAddress;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
16 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceClassName;
17 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceFlowDirection;
18 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccaps.Ccap;
19 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.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,
140 final ServiceFlowDirection scnDir) {
142 GateSendStatus status = new GateSendStatus();
144 logger.info("Sending gate to CCAP with ID - " + ccap.getCcapId());
146 // assemble the gate request for this subId
147 final PCMMGateReqBuilder gateBuilder = new PCMMGateReqBuilder();
148 gateBuilder.setAmId(ccap.getAmId());
149 gateBuilder.setSubscriberId(subId);
151 // force gateSpec.Direction to align with SCN direction
152 final ServiceClassName scn = qosGate.getTrafficProfile().getServiceClassName();
154 gateBuilder.setGateSpec(qosGate.getGateSpec(), scnDir);
157 gateBuilder.setGateSpec(qosGate.getGateSpec(), null);
159 gateBuilder.setTrafficProfile(qosGate.getTrafficProfile());
161 gateBuilder.setClassifiers(qosGate.getClassifiers().getClassifierContainer());
163 // assemble the final gate request
164 final PCMMGateReq gateReq = gateBuilder.build();
166 if (gateRequests.get(gatePathStr) == null) {
168 gateRequests.put(gatePathStr, gateReq);
169 // and send it to the CCAP
170 ccapClient.sendGateSet(gateReq);
171 // and wait for the COPS response to complete processing gate request
173 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
174 // TODO - handle this synchronization.
175 // TODO - if not changing this, may want to make this timeout configurable
176 synchronized (gateReq) {
177 logger.info("Waiting 5000ms for gate request to be updated");
179 logger.debug("Gate request error - " + gateReq.getError());
180 logger.debug("Gate request ID - " + gateReq.getGateID());
182 } catch (Exception e) {
184 "PCMMService: sendGateSet(): gate response timeout exceeded for " + gatePathStr + '/' + gateReq,
186 status.setDidSucceed(false);
187 status.setMessage(String.format("408 Request Timeout - gate response timeout exceeded for %s/%s", ccap.getCcapId(),
193 if (gateReq.getError() != null) {
194 gateRequests.remove(gatePathStr);
195 status.setDidSucceed(false);
197 String.format("404 Not Found - sendGateSet for %s/%s returned error - %s", ccap.getCcapId(),
198 gatePathStr, gateReq.getError().toString()));
200 logger.error("PCMMService: sendGateSet(): returned error: {}", gateReq.getError().toString());
202 if (gateReq.getGateID() != null) {
203 status.setDidSucceed(true);
204 status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
205 status.setMessage(String.format("200 OK - sendGateSet for %s/%s returned GateId %08x",
206 ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
207 logger.info(String.format("PCMMService: sendGateSet(): returned GateId %08x: ",
208 gateReq.getGateID().getGateID()));
210 status.setDidSucceed(false);
212 String.format("404 Not Found - sendGateSet for %s/%s no gateId returned", ccap.getCcapId(),
215 logger.info("PCMMService: sendGateSet(): no gateId returned:");
219 logger.info("PCMMService: sendGateSet(): no gateId returned:");
220 status.setMessage(String.format("404 Not Found - sendGateSet for %s/%s already exists", ccap.getCcapId(), gatePathStr));
226 public Boolean sendGateDelete(final String gatePathStr) {
227 logger.info("sendGateDelete() - " + ccap);
228 // recover the original gate request
229 final PCMMGateReq gateReq = gateRequests.remove(gatePathStr);
230 if (gateReq != null) {
231 ccapClient.sendGateDelete(gateReq);
232 // and wait for the response to complete
234 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
235 // TODO - handle this synchronization.
236 synchronized (gateReq) {
239 } catch (InterruptedException e) {
240 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}", gatePathStr,
243 if (gateReq.getError() != null) {
244 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
247 if (gateReq.getGateID() != null) {
248 logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ",
249 gateReq.getGateID().getGateID()));
251 logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
256 logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
261 public Boolean getPcmmPdpSocket() {
263 return ccapClient.pcmmPdp.getSocket().isClosed();
264 } catch (Exception e) {
265 logger.error("getPcmmPdpSocket: {} FAILED: {}", ccapClient, e.getMessage());
270 public Boolean getPcmmCcapClientIsConnected() {
272 return ccapClient.isConnected;
273 } catch (Exception e) {
274 logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
279 public String getPcmmCcapClientConnectErrMsg() {
281 return ccapClient.errMessage;
282 } catch (Exception e) {
283 logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
284 return e.getMessage();
288 //new gate-info method
289 public GateSendStatus sendGateInfo(final String gatePathStr) {
291 logger.info("sendGateInfo() - " + ccap);
293 GateSendStatus status = new GateSendStatus();
295 // recover the original gate request
296 final PCMMGateReq gateReq = gateRequests.get(gatePathStr);
298 // is the ccap socket open?
299 final Boolean socketIsClosed = getPcmmPdpSocket();
301 if ((gateReq != null) && (!socketIsClosed)) {
302 gateReq.setTransactionID(new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
303 ITransactionID.GateCommandType.GATE_INFO));
305 ccapClient.sendGateInfo(gateReq);
306 // and wait for the response to complete
308 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
309 // TODO - handle this synchronization.
310 synchronized (gateReq) {
311 logger.info("Waiting 5000ms for gate request to be updated");
313 logger.debug("Gate request error - " + gateReq.getError());
314 logger.debug("Gate request ID - " + gateReq.getGateID());
316 } catch (InterruptedException e) {
317 status.setDidSucceed(false);
318 status.setMessage(String.format("Gate-Info Request Timeout for %s", ccap.getCcapId()));
321 if (gateReq.getError() != null) {
322 status.setDidSucceed(false);
324 String.format("%s reports '%s'", ccap.getCcapId(), gateReq.getError().toString()));
325 logger.error("PCMMService: sendGateInfo(): returned error: {}", gateReq.getError().toString());
327 if (gateReq.getGateID() != null) {
328 status.setDidSucceed(true);
329 status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
330 //status.setMessage(String.format("200 OK - sendGateInfo for %s/%s returned GateId %08x",
331 // ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
333 final IGateState gateState = gateReq.getGateState();
334 status.setCopsGateState(gateState.getGateState().toString());
335 status.setCopsGateStateReason(gateState.getGateStateReason().toString());
336 status.setCopsGateTimeInfo(String.format("%d", gateReq.getGateTimeInfo().getGateTimeInfo()));
337 status.setCopsGateUsageInfo(String.format("%d", gateReq.getGateUsageInfo().getGateUsageInfo()));
338 logger.info(String.format("PCMMService: sendGateInfo(): returned GateId %08x: ",
339 gateReq.getGateID().getGateID()));
341 status.setDidSucceed(false);
343 String.format("404 Not Found - sendGateInfo for %s/%s no gateId returned", ccap.getCcapId(),
346 logger.info("PCMMService: sendGateInfo(): no gateId returned:");
351 status.setDidSucceed(false);
352 if (socketIsClosed) {
353 status.setMessage(String.format("%s: CCAP Cops Socket is closed",ccap.getCcapId()));
356 status.setMessage( String.format("Attempt to get info of non-existent gate with path - " + gatePathStr));
365 * Used to interface with a CCAP (including CMTSs)
367 protected class CcapClient {
368 public final PCMMPdpDataProcess pcmmProcess;
369 public final PCMMPdpAgent pcmmPdp;
371 private final String ipv4;
372 private final Integer port;
374 // Needs to be initialized in connect() method else would be final
375 protected transient PCMMPdpMsgSender pcmmSender;
377 private transient Boolean isConnected = false;
378 private transient String errMessage = null;
384 * - the IP of the CCAP to manage
386 * - the port number of the CCAP to manage
388 public CcapClient(final IpAddress ccapIp, final PortNumber portNum) {
389 ipv4 = ccapIp.getIpv4Address().getValue();
390 if (portNum != null) {
391 port = portNum.getValue();
393 port = PCMMPdpAgent.WELL_KNOWN_PDP_PORT;
395 // TODO FIXME - if this object is not null, gate processing will not work correctly
396 // TODO see - PCMMPdpReqStateMan#processReport() where the report type is success and the process is null
397 // pcmmProcess = new PCMMPdpDataProcess();
399 pcmmPdp = new PCMMPdpAgent(ipv4, port, clientType, pcmmProcess);
403 * Starts the connection to the CCAP
405 public void connect() {
406 logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
411 // Cannot instantiate until after pcmmPdp.connect() is called as this is where the client handle is created
412 pcmmSender = new PCMMPdpMsgSender(clientType, pcmmPdp.getClientHandle(), pcmmPdp.getSocket());
415 } catch (Exception e) {
417 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
418 errMessage = e.getMessage();
422 public void disconnect() {
423 logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
424 pcmmPdp.disconnect(new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
428 // TODO - consider returning a new PCMMGateReq object or a future here instead of setting the ID on the old
429 // TODO - request by reference which makes the code more convoluted thus making issues more difficult to track down.
430 public Boolean sendGateSet(final PCMMGateReq gateReq) {
431 logger.info("CcapClient: sendGateSet(): {}:{} => {}", ipv4, port, gateReq);
433 pcmmSender.sendGateSet(gateReq);
435 // TODO - determine if this is the correct place to perform this operation as this currently is the
436 // TODO - place where the gate ID can be set on the gateReq object
437 // pcmmSender.handleGateReport(pcmmPdp.getSocket());
438 } catch (COPSPdpException e) {
439 logger.error("CcapClient: sendGateSet(): {}:{} => {} FAILED:", ipv4, port, gateReq, e);
441 // and save it back to the gateRequest object for gate delete later
442 gateReq.setGateID(pcmmSender.getGateID());
444 // TODO - determine why this method is always returning true???
448 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
449 logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
451 pcmmSender.sendGateDelete(gateReq);
452 } catch (COPSPdpException e) {
453 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq,
459 public Boolean sendGateInfo(final PCMMGateReq gateReq) {
460 logger.info("CcapClient: sendGateInfo(): {}:{} => {}", ipv4, port);
462 pcmmSender.sendGateInfo(gateReq);
463 } catch (COPSPdpException e) {
464 logger.error("CcapClient: sendGateInfo(): {}:{} => {} FAILED: {}", ipv4, port,