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.rev151026.ServiceClassName;
17 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ServiceFlowDirection;
18 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ccaps.Ccap;
19 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.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 // pick a classifier type (only one for now)
127 if (qosGate.getClassifier() != null) {
128 gateBuilder.setClassifier(qosGate.getClassifier());
129 } else if (qosGate.getExtClassifier() != null) {
130 gateBuilder.setExtClassifier(qosGate.getExtClassifier());
131 } else if (qosGate.getIpv6Classifier() != null) {
132 gateBuilder.setIpv6Classifier(qosGate.getIpv6Classifier());
135 // assemble the final gate request
136 final PCMMGateReq gateReq = gateBuilder.build();
138 if (gateRequests.get(gatePathStr) == null) {
140 gateRequests.put(gatePathStr, gateReq);
141 // and send it to the CCAP
142 ccapClient.sendGateSet(gateReq);
143 // and wait for the COPS response to complete processing gate request
145 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
146 // TODO - handle this synchronization.
147 // TODO - if not changing this, may want to make this timeout configurable
148 synchronized (gateReq) {
149 logger.info("Waiting 5000ms for gate request to be updated");
151 logger.debug("Gate request error - " + gateReq.getError());
152 logger.debug("Gate request ID - " + gateReq.getGateID());
154 } catch (Exception e) {
156 "PCMMService: sendGateSet(): gate response timeout exceeded for " + gatePathStr + '/' + gateReq,
158 status.setDidSucceed(false);
159 status.setMessage(String.format("408 Request Timeout - gate response timeout exceeded for %s/%s", ccap.getCcapId(),
165 if (gateReq.getError() != null) {
166 status.setDidSucceed(false);
168 String.format("404 Not Found - sendGateSet for %s/%s returned error - %s", ccap.getCcapId(),
169 gatePathStr, gateReq.getError().toString()));
171 logger.error("PCMMService: sendGateSet(): returned error: {}", gateReq.getError().toString());
173 if (gateReq.getGateID() != null) {
174 status.setDidSucceed(true);
175 status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
176 status.setMessage(String.format("200 OK - sendGateSet for %s/%s returned GateId %08x",
177 ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
178 logger.info(String.format("PCMMService: sendGateSet(): returned GateId %08x: ",
179 gateReq.getGateID().getGateID()));
181 status.setDidSucceed(false);
183 String.format("404 Not Found - sendGateSet for %s/%s no gateId returned", ccap.getCcapId(),
186 logger.info("PCMMService: sendGateSet(): no gateId returned:");
190 logger.info("PCMMService: sendGateSet(): no gateId returned:");
191 status.setMessage(String.format("404 Not Found - sendGateSet for %s/%s already exists", ccap.getCcapId(), gatePathStr));
197 public Boolean sendGateDelete(final String gatePathStr) {
198 logger.info("sendGateDelete() - " + ccap);
199 // recover the original gate request
200 final PCMMGateReq gateReq = gateRequests.remove(gatePathStr);
201 if (gateReq != null) {
202 ccapClient.sendGateDelete(gateReq);
203 // and wait for the response to complete
205 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
206 // TODO - handle this synchronization.
207 synchronized (gateReq) {
210 } catch (InterruptedException e) {
211 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}", gatePathStr,
214 if (gateReq.getError() != null) {
215 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
218 if (gateReq.getGateID() != null) {
219 logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ",
220 gateReq.getGateID().getGateID()));
222 logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
227 logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
233 * Used to interface with a CCAP (including CMTSs)
235 protected class CcapClient {
236 public final PCMMPdpDataProcess pcmmProcess;
237 public final PCMMPdpAgent pcmmPdp;
239 private final String ipv4;
240 private final Integer port;
242 // Needs to be initialized in connect() method else would be final
243 protected transient PCMMPdpMsgSender pcmmSender;
245 private transient Boolean isConnected = false;
246 private transient String errMessage = null;
252 * - the IP of the CCAP to manage
254 * - the port number of the CCAP to manage
256 public CcapClient(final IpAddress ccapIp, final PortNumber portNum) {
257 ipv4 = ccapIp.getIpv4Address().getValue();
258 if (portNum != null) {
259 port = portNum.getValue();
261 port = PCMMPdpAgent.WELL_KNOWN_PDP_PORT;
263 // TODO FIXME - if this object is not null, gate processing will not work correctly
264 // TODO see - PCMMPdpReqStateMan#processReport() where the report type is success and the process is null
265 // pcmmProcess = new PCMMPdpDataProcess();
267 pcmmPdp = new PCMMPdpAgent(ipv4, port, clientType, pcmmProcess);
271 * Starts the connection to the CCAP
273 public void connect() {
274 logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
278 // Cannot instantiate until after pcmmPdp.connect() is called as this is where the client handle is created
279 pcmmSender = new PCMMPdpMsgSender(clientType, pcmmPdp.getClientHandle(), pcmmPdp.getSocket());
282 } catch (Exception e) {
284 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
285 errMessage = e.getMessage();
289 public void disconnect() {
290 logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
291 pcmmPdp.disconnect(new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
295 // TODO - consider returning a new PCMMGateReq object or a future here instead of setting the ID on the old
296 // TODO - request by reference which makes the code more convoluted thus making issues more difficult to track down.
297 public Boolean sendGateSet(final PCMMGateReq gateReq) {
298 logger.info("CcapClient: sendGateSet(): {}:{} => {}", ipv4, port, gateReq);
300 pcmmSender.sendGateSet(gateReq);
302 // TODO - determine if this is the correct place to perform this operation as this currently is the
303 // TODO - place where the gate ID can be set on the gateReq object
304 // pcmmSender.handleGateReport(pcmmPdp.getSocket());
305 } catch (COPSPdpException e) {
306 logger.error("CcapClient: sendGateSet(): {}:{} => {} FAILED:", ipv4, port, gateReq, e);
308 // and save it back to the gateRequest object for gate delete later
309 gateReq.setGateID(pcmmSender.getGateID());
311 // TODO - determine why this method is always returning true???
315 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
316 logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
318 pcmmSender.sendGateDelete(gateReq);
319 } catch (COPSPdpException e) {
320 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq,