2 * (c) 2015 Cable Television Laboratories, Inc. All rights reserved.
5 package org.opendaylight.controller.packetcable.provider;
7 import com.google.common.collect.Maps;
8 import java.net.InetAddress;
10 import javax.annotation.concurrent.ThreadSafe;
11 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
12 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
13 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ServiceClassName;
14 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ServiceFlowDirection;
15 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ccaps.Ccap;
16 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
17 import org.pcmm.PCMMPdpAgent;
18 import org.pcmm.PCMMPdpDataProcess;
19 import org.pcmm.PCMMPdpMsgSender;
20 import org.pcmm.gates.impl.PCMMGateReq;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 import org.umu.cops.prpdp.COPSPdpException;
24 import org.umu.cops.stack.COPSError;
25 import org.umu.cops.stack.COPSError.ErrorTypes;
28 * Class responsible for managing the gates for a single CCAP.
31 public class PCMMService {
32 private Logger logger = LoggerFactory.getLogger(PCMMService.class);
34 private final Ccap ccap;
35 private final IpAddress ipAddr;
36 private final PortNumber portNum;
37 protected final CcapClient ccapClient;
38 protected Map<String, PCMMGateReq> gateRequests = Maps.newConcurrentMap();
40 private final short clientType;
42 public PCMMService(final short clientType, final Ccap ccap) {
43 this.clientType = clientType;
45 ipAddr = ccap.getConnection().getIpAddress();
46 portNum = ccap.getConnection().getPort();
47 ccapClient = new CcapClient(ipAddr, portNum);
48 logger.info("Attempting to add CCAP with ID {} @ {}:{}", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(),
52 public void disconect() {
53 ccapClient.disconnect();
56 // TODO - try and change the return to something other than a String to be parsed to determine success
57 public String addCcap() {
59 if (ccapClient.isConnected) {
60 logger.info("Connected to CCAP with ID - " + ccap.getCcapId());
61 return String.format("200 OK - CCAP %s connected @ %s:%d", ccap.getCcapId(),
62 ipAddr.getIpv4Address().getValue(), portNum.getValue());
64 return String.format("404 Not Found - CCAP %s failed to connect @ %s:%d - %s",
66 ipAddr.getIpv4Address().getValue(), portNum.getValue(), ccapClient.errMessage);
70 // TODO - Consider creating an object to return that contains a success flag, message, and gate ID or gate object
71 public String sendGateSet(final String gatePathStr, final InetAddress subId, final Gate qosGate,
72 final ServiceFlowDirection scnDir) {
73 logger.info("Sending gate to CCAP with ID - " + ccap.getCcapId());
74 // assemble the gate request for this subId
75 final PCMMGateReqBuilder gateBuilder = new PCMMGateReqBuilder();
76 gateBuilder.setAmId(ccap.getAmId());
77 gateBuilder.setSubscriberId(subId);
78 // force gateSpec.Direction to align with SCN direction
79 final ServiceClassName scn = qosGate.getTrafficProfile().getServiceClassName();
81 gateBuilder.setGateSpec(qosGate.getGateSpec(), scnDir);
84 gateBuilder.setGateSpec(qosGate.getGateSpec(), null);
86 gateBuilder.setTrafficProfile(qosGate.getTrafficProfile());
88 // pick a classifier type (only one for now)
89 if (qosGate.getClassifier() != null) {
90 gateBuilder.setClassifier(qosGate.getClassifier());
91 } else if (qosGate.getExtClassifier() != null) {
92 gateBuilder.setExtClassifier(qosGate.getExtClassifier());
93 } else if (qosGate.getIpv6Classifier() != null) {
94 gateBuilder.setIpv6Classifier(qosGate.getIpv6Classifier());
96 // assemble the final gate request
97 final PCMMGateReq gateReq = gateBuilder.build();
99 if (gateRequests.get(gatePathStr) == null) {
101 gateRequests.put(gatePathStr, gateReq);
102 // and send it to the CCAP
103 ccapClient.sendGateSet(gateReq);
104 // and wait for the COPS response to complete processing gate request
106 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
107 // TODO - handle this synchronization.
108 // TODO - if not changing this, may want to make this timeout configurable
109 synchronized(gateReq) {
110 logger.info("Waiting 5000ms for gate request to be updated");
112 logger.debug("Gate request error - " + gateReq.getError());
113 logger.debug("Gate request ID - " + gateReq.getGateID());
115 } catch (Exception e) {
116 logger.error("PCMMService: sendGateSet(): gate response timeout exceeded for "
117 + gatePathStr + '/' + gateReq, e);
118 return String.format("408 Request Timeout - gate response timeout exceeded for %s/%s",
119 ccap.getCcapId(), gatePathStr);
121 if (gateReq.getError() != null) {
122 logger.error("PCMMService: sendGateSet(): returned error: {}",
123 gateReq.getError().toString());
124 return String.format("404 Not Found - sendGateSet for %s/%s returned error - %s",
125 ccap.getCcapId(), gatePathStr, gateReq.getError().toString());
127 if (gateReq.getGateID() != null) {
128 logger.info(String.format("PCMMService: sendGateSet(): returned GateId %08x: ",
129 gateReq.getGateID().getGateID()));
130 return String.format("200 OK - sendGateSet for %s/%s returned GateId %08x",
131 ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID());
133 logger.info("PCMMService: sendGateSet(): no gateId returned:");
134 return String.format("404 Not Found - sendGateSet for %s/%s no gateId returned",
135 ccap.getCcapId(), gatePathStr);
139 logger.info("PCMMService: sendGateSet(): no gateId returned:");
140 return String.format("404 Not Found - sendGateSet for %s/%s already exists",
141 ccap.getCcapId(), gatePathStr);
145 public Boolean sendGateDelete(final String gatePathStr) {
146 logger.info("sendGateDelete() - " + ccap);
147 // recover the original gate request
148 final PCMMGateReq gateReq = gateRequests.remove(gatePathStr);
149 if (gateReq != null) {
150 ccapClient.sendGateDelete(gateReq);
151 // and wait for the response to complete
153 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
154 // TODO - handle this synchronization.
155 synchronized(gateReq) {
158 } catch (InterruptedException e) {
159 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}",
160 gatePathStr, gateReq);
162 if (gateReq.getError() != null) {
163 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
166 if (gateReq.getGateID() != null) {
167 logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ", gateReq.getGateID().getGateID()));
169 logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
174 logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
180 * Used to interface with a CCAP (including CMTSs)
182 protected class CcapClient {
183 public final PCMMPdpDataProcess pcmmProcess;
184 public final PCMMPdpAgent pcmmPdp;
186 private final String ipv4;
187 private final Integer port;
189 // Needs to be initialized in connect() method else would be final
190 protected transient PCMMPdpMsgSender pcmmSender;
192 private transient Boolean isConnected = false;
193 private transient String errMessage = null;
197 * @param ccapIp - the IP of the CCAP to manage
198 * @param portNum - the port number of the CCAP to manage
200 public CcapClient(final IpAddress ccapIp, final PortNumber portNum) {
201 ipv4 = ccapIp.getIpv4Address().getValue();
202 if (portNum != null) port = portNum.getValue();
203 else port = PCMMPdpAgent.WELL_KNOWN_PDP_PORT;
204 // TODO FIXME - if this object is not null, gate processing will not work correctly
205 // TODO see - PCMMPdpReqStateMan#processReport() where the report type is success and the process is null
206 // pcmmProcess = new PCMMPdpDataProcess();
208 pcmmPdp = new PCMMPdpAgent(ipv4, port, clientType, pcmmProcess);
212 * Starts the connection to the CCAP
214 public void connect( ) {
215 logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
219 // Cannot instantiate until after pcmmPdp.connect() is called as this is where the client handle is created
220 pcmmSender = new PCMMPdpMsgSender(clientType, pcmmPdp.getClientHandle(), pcmmPdp.getSocket());
223 } catch (Exception e) {
225 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
226 errMessage = e.getMessage();
230 public void disconnect() {
231 logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
232 pcmmPdp.disconnect(new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
236 // TODO - consider returning a new PCMMGateReq object or a future here instead of setting the ID on the old
237 // TODO - request by reference which makes the code more convoluted thus making issues more difficult to track down.
238 public Boolean sendGateSet(final PCMMGateReq gateReq) {
239 logger.info("CcapClient: sendGateSet(): {}:{} => {}", ipv4, port, gateReq);
241 pcmmSender.sendGateSet(gateReq);
243 // TODO - determine if this is the correct place to perform this operation as this currently is the
244 // TODO - place where the gate ID can be set on the gateReq object
245 // pcmmSender.handleGateReport(pcmmPdp.getSocket());
246 } catch (COPSPdpException e) {
247 logger.error("CcapClient: sendGateSet(): {}:{} => {} FAILED:", ipv4, port, gateReq, e);
249 // and save it back to the gateRequest object for gate delete later
250 gateReq.setGateID(pcmmSender.getGateID());
252 // TODO - determine why this method is always returning true???
256 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
257 logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
259 pcmmSender.sendGateDelete(gateReq);
260 } catch (COPSPdpException e) {
261 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq, e.getMessage());