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.impl.PCMMGateReq;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import org.umu.cops.prpdp.COPSPdpException;
27 import org.umu.cops.stack.COPSError;
28 import org.umu.cops.stack.COPSError.ErrorTypes;
31 * Class responsible for managing the gates for a single CCAP.
34 public class PCMMService {
35 private final Logger logger = LoggerFactory.getLogger(PCMMService.class);
37 private final Ccap ccap;
38 private final IpAddress ipAddr;
39 private final PortNumber portNum;
40 protected final CcapClient ccapClient;
41 protected Map<String, PCMMGateReq> gateRequests = Maps.newConcurrentMap();
43 private final short clientType;
45 public PCMMService(final short clientType, final Ccap ccap) {
46 this.clientType = clientType;
48 ipAddr = ccap.getConnection().getIpAddress();
49 portNum = ccap.getConnection().getPort();
50 ccapClient = new CcapClient(ipAddr, portNum);
51 logger.info("Attempting to add CCAP with ID {} @ {}:{}", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(),
55 public void disconect() {
56 ccapClient.disconnect();
59 // TODO - try and change the return to something other than a String to be parsed to determine success
60 public String addCcap() {
62 if (ccapClient.isConnected) {
63 logger.info("Connected to CCAP with ID - " + ccap.getCcapId());
65 .format("200 OK - CCAP %s connected @ %s:%d", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(),
68 return String.format("404 Not Found - CCAP %s failed to connect @ %s:%d - %s", ccap.getCcapId(),
69 ipAddr.getIpv4Address().getValue(), portNum.getValue(), ccapClient.errMessage);
73 public class GateSetStatus {
74 private boolean didSucceed = false;
75 private String message = "";
76 private String copsGateId = "";
78 public boolean didSucceed() {
82 void setDidSucceed(final boolean didSucceed) {
83 this.didSucceed = didSucceed;
86 public String getMessage() {
90 void setMessage(final String message) {
91 this.message = message;
94 public String getCopsGateId() {
98 void setCopsGateId(final String copsGateId) {
99 this.copsGateId = copsGateId;
104 public GateSetStatus sendGateSet(final String gatePathStr, final InetAddress subId, final Gate qosGate,
105 final ServiceFlowDirection scnDir) {
107 GateSetStatus status = new GateSetStatus();
109 logger.info("Sending gate to CCAP with ID - " + ccap.getCcapId());
111 // assemble the gate request for this subId
112 final PCMMGateReqBuilder gateBuilder = new PCMMGateReqBuilder();
113 gateBuilder.setAmId(ccap.getAmId());
114 gateBuilder.setSubscriberId(subId);
116 // force gateSpec.Direction to align with SCN direction
117 final ServiceClassName scn = qosGate.getTrafficProfile().getServiceClassName();
119 gateBuilder.setGateSpec(qosGate.getGateSpec(), scnDir);
122 gateBuilder.setGateSpec(qosGate.getGateSpec(), null);
124 gateBuilder.setTrafficProfile(qosGate.getTrafficProfile());
126 gateBuilder.setClassifiers(qosGate.getClassifiers().getClassifierContainer());
128 // assemble the final gate request
129 final PCMMGateReq gateReq = gateBuilder.build();
131 if (gateRequests.get(gatePathStr) == null) {
133 gateRequests.put(gatePathStr, gateReq);
134 // and send it to the CCAP
135 ccapClient.sendGateSet(gateReq);
136 // and wait for the COPS response to complete processing gate request
138 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
139 // TODO - handle this synchronization.
140 // TODO - if not changing this, may want to make this timeout configurable
141 synchronized (gateReq) {
142 logger.info("Waiting 5000ms for gate request to be updated");
144 logger.debug("Gate request error - " + gateReq.getError());
145 logger.debug("Gate request ID - " + gateReq.getGateID());
147 } catch (Exception e) {
149 "PCMMService: sendGateSet(): gate response timeout exceeded for " + gatePathStr + '/' + gateReq,
151 status.setDidSucceed(false);
152 status.setMessage(String.format("408 Request Timeout - gate response timeout exceeded for %s/%s", ccap.getCcapId(),
158 if (gateReq.getError() != null) {
159 gateRequests.remove(gatePathStr);
160 status.setDidSucceed(false);
162 String.format("404 Not Found - sendGateSet for %s/%s returned error - %s", ccap.getCcapId(),
163 gatePathStr, gateReq.getError().toString()));
165 logger.error("PCMMService: sendGateSet(): returned error: {}", gateReq.getError().toString());
167 if (gateReq.getGateID() != null) {
168 status.setDidSucceed(true);
169 status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
170 status.setMessage(String.format("200 OK - sendGateSet for %s/%s returned GateId %08x",
171 ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
172 logger.info(String.format("PCMMService: sendGateSet(): returned GateId %08x: ",
173 gateReq.getGateID().getGateID()));
175 status.setDidSucceed(false);
177 String.format("404 Not Found - sendGateSet for %s/%s no gateId returned", ccap.getCcapId(),
180 logger.info("PCMMService: sendGateSet(): no gateId returned:");
184 logger.info("PCMMService: sendGateSet(): no gateId returned:");
185 status.setMessage(String.format("404 Not Found - sendGateSet for %s/%s already exists", ccap.getCcapId(), gatePathStr));
191 public Boolean sendGateDelete(final String gatePathStr) {
192 logger.info("sendGateDelete() - " + ccap);
193 // recover the original gate request
194 final PCMMGateReq gateReq = gateRequests.remove(gatePathStr);
195 if (gateReq != null) {
196 ccapClient.sendGateDelete(gateReq);
197 // and wait for the response to complete
199 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
200 // TODO - handle this synchronization.
201 synchronized (gateReq) {
204 } catch (InterruptedException e) {
205 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}", gatePathStr,
208 if (gateReq.getError() != null) {
209 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
212 if (gateReq.getGateID() != null) {
213 logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ",
214 gateReq.getGateID().getGateID()));
216 logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
221 logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
227 * Used to interface with a CCAP (including CMTSs)
229 protected class CcapClient {
230 public final PCMMPdpDataProcess pcmmProcess;
231 public final PCMMPdpAgent pcmmPdp;
233 private final String ipv4;
234 private final Integer port;
236 // Needs to be initialized in connect() method else would be final
237 protected transient PCMMPdpMsgSender pcmmSender;
239 private transient Boolean isConnected = false;
240 private transient String errMessage = null;
246 * - the IP of the CCAP to manage
248 * - the port number of the CCAP to manage
250 public CcapClient(final IpAddress ccapIp, final PortNumber portNum) {
251 ipv4 = ccapIp.getIpv4Address().getValue();
252 if (portNum != null) {
253 port = portNum.getValue();
255 port = PCMMPdpAgent.WELL_KNOWN_PDP_PORT;
257 // TODO FIXME - if this object is not null, gate processing will not work correctly
258 // TODO see - PCMMPdpReqStateMan#processReport() where the report type is success and the process is null
259 // pcmmProcess = new PCMMPdpDataProcess();
261 pcmmPdp = new PCMMPdpAgent(ipv4, port, clientType, pcmmProcess);
265 * Starts the connection to the CCAP
267 public void connect() {
268 logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
272 // Cannot instantiate until after pcmmPdp.connect() is called as this is where the client handle is created
273 pcmmSender = new PCMMPdpMsgSender(clientType, pcmmPdp.getClientHandle(), pcmmPdp.getSocket());
276 } catch (Exception e) {
278 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
279 errMessage = e.getMessage();
283 public void disconnect() {
284 logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
285 pcmmPdp.disconnect(new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
289 // TODO - consider returning a new PCMMGateReq object or a future here instead of setting the ID on the old
290 // TODO - request by reference which makes the code more convoluted thus making issues more difficult to track down.
291 public Boolean sendGateSet(final PCMMGateReq gateReq) {
292 logger.info("CcapClient: sendGateSet(): {}:{} => {}", ipv4, port, gateReq);
294 pcmmSender.sendGateSet(gateReq);
296 // TODO - determine if this is the correct place to perform this operation as this currently is the
297 // TODO - place where the gate ID can be set on the gateReq object
298 // pcmmSender.handleGateReport(pcmmPdp.getSocket());
299 } catch (COPSPdpException e) {
300 logger.error("CcapClient: sendGateSet(): {}:{} => {} FAILED:", ipv4, port, gateReq, e);
302 // and save it back to the gateRequest object for gate delete later
303 gateReq.setGateID(pcmmSender.getGateID());
305 // TODO - determine why this method is always returning true???
309 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
310 logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
312 pcmmSender.sendGateDelete(gateReq);
313 } catch (COPSPdpException e) {
314 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq,