1 package org.opendaylight.controller.packetcable.provider;
3 import com.google.common.collect.Maps;
4 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
5 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
6 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceClassName;
7 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceFlowDirection;
8 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.Ccaps;
9 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.Gates;
10 import org.pcmm.PCMMPdpAgent;
11 import org.pcmm.PCMMPdpDataProcess;
12 import org.pcmm.PCMMPdpMsgSender;
13 import org.pcmm.gates.impl.PCMMGateReq;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.umu.cops.prpdp.COPSPdpException;
17 import org.umu.cops.stack.COPSError;
18 import org.umu.cops.stack.COPSError.ErrorTypes;
19 import org.umu.cops.stack.COPSException;
21 import javax.annotation.concurrent.ThreadSafe;
22 import java.io.IOException;
23 import java.net.InetAddress;
27 * Class responsible for managing the gates for a single CCAP.
30 public class PCMMService {
31 private Logger logger = LoggerFactory.getLogger(PCMMService.class);
33 private final Ccaps ccap;
34 private final IpAddress ipAddr;
35 private final PortNumber portNum;
36 protected final CcapClient ccapClient;
37 protected Map<String, PCMMGateReq> gateRequests = Maps.newConcurrentMap();
39 private final short clientType;
41 public PCMMService(final short clientType, final Ccaps ccap) {
42 this.clientType = clientType;
44 ipAddr = ccap.getConnection().getIpAddress();
45 portNum = ccap.getConnection().getPort();
46 ccapClient = new CcapClient(ipAddr, portNum);
47 logger.info("Attempting to add CCAP with ID {} @ {}:{}", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(), portNum.getValue());
50 public void disconect() {
51 ccapClient.disconnect();
54 // TODO - try and change the return to something other than a String to be parsed to determine success
55 public String addCcap() {
57 if (ccapClient.isConnected) {
58 logger.info("Connected to CCAP with ID - " + ccap.getCcapId());
59 return String.format("200 OK - CCAP %s connected @ %s:%d", ccap.getCcapId(),
60 ipAddr.getIpv4Address().getValue(), portNum.getValue());
62 return String.format("404 Not Found - CCAP %s failed to connect @ %s:%d - %s",
64 ipAddr.getIpv4Address().getValue(), portNum.getValue(), ccapClient.errMessage);
68 // TODO - Consider creating an object to return that contains a success flag, message, and gate ID or gate object
69 // TODO FIXME - the gate appears to be getting set as per restconf but I am not seeing the proper logging occurring
70 public String sendGateSet(final String gatePathStr, final InetAddress subId, final Gates qosGate,
71 final ServiceFlowDirection scnDir) {
72 logger.info("Sending gate to CCAP with ID - " + ccap.getCcapId());
73 // assemble the gate request for this subId
74 final PCMMGateReqBuilder gateBuilder = new PCMMGateReqBuilder();
75 gateBuilder.build(ccap.getAmId());
76 gateBuilder.build(subId);
77 // force gateSpec.Direction to align with SCN direction
78 final ServiceClassName scn = qosGate.getTrafficProfile().getServiceClassName();
80 gateBuilder.build(qosGate.getGateSpec(), scnDir);
83 gateBuilder.build(qosGate.getGateSpec(), null);
85 gateBuilder.build(qosGate.getTrafficProfile());
87 // pick a classifier type (only one for now)
88 if (qosGate.getClassifier() != null) {
89 gateBuilder.build(qosGate.getClassifier());
90 } else if (qosGate.getExtClassifier() != null) {
91 gateBuilder.build(qosGate.getExtClassifier());
92 } else if (qosGate.getIpv6Classifier() != null) {
93 gateBuilder.build(qosGate.getIpv6Classifier());
95 // assemble the final gate request
96 final PCMMGateReq gateReq = gateBuilder.getGateReq();
99 gateRequests.put(gatePathStr, gateReq);
100 // and send it to the CCAP
101 ccapClient.sendGateSet(gateReq);
102 // and wait for the COPS response to complete processing gate request
104 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
105 // TODO - handle this synchronization.
106 // TODO - if not changing this, may want to make this timeout configurable
107 synchronized(gateReq) {
108 logger.info("Waiting 1000ms for gate request to be updated");
110 logger.debug("Gate request error - " + gateReq.getError());
111 logger.debug("Gate request ID - " + gateReq.getGateID());
113 } catch (Exception e) {
114 logger.error("PCMMService: sendGateSet(): gate response timeout exceeded for "
115 + gatePathStr + '/' + gateReq, e);
116 return String.format("408 Request Timeout - gate response timeout exceeded for %s/%s",
117 ccap.getCcapId(), gatePathStr);
119 if (gateReq.getError() != null) {
120 logger.error("PCMMService: sendGateSet(): returned error: {}",
121 gateReq.getError().toString());
122 return String.format("404 Not Found - sendGateSet for %s/%s returned error - %s",
123 ccap.getCcapId(), gatePathStr, gateReq.getError().toString());
125 if (gateReq.getGateID() != null) {
126 logger.info(String.format("PCMMService: sendGateSet(): returned GateId %08x: ",
127 gateReq.getGateID().getGateID()));
128 return String.format("200 OK - sendGateSet for %s/%s returned GateId %08x",
129 ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID());
131 logger.info("PCMMService: sendGateSet(): no gateId returned:");
132 return String.format("404 Not Found - sendGateSet for %s/%s no gateId returned",
133 ccap.getCcapId(), gatePathStr);
138 public Boolean sendGateDelete(final String gatePathStr) {
139 logger.info("sendGateDelete() - " + ccap);
140 // recover the original gate request
141 final PCMMGateReq gateReq = gateRequests.remove(gatePathStr);
142 if (gateReq != null) {
143 ccapClient.sendGateDelete(gateReq);
144 // and wait for the response to complete
146 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
147 // TODO - handle this synchronization.
148 synchronized(gateReq) {
151 } catch (InterruptedException e) {
152 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}",
153 gatePathStr, gateReq);
155 if (gateReq.getError() != null) {
156 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
159 if (gateReq.getGateID() != null) {
160 logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ", gateReq.getGateID().getGateID()));
162 logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
172 * Used to interface with a CCAP (including CMTSs)
174 protected class CcapClient {
175 public final PCMMPdpDataProcess pcmmProcess;
176 public final PCMMPdpAgent pcmmPdp;
178 private final String ipv4;
179 private final Integer port;
181 // Needs to be initialized in connect() method else would be final
182 protected transient PCMMPdpMsgSender pcmmSender;
184 private transient Boolean isConnected = false;
185 private transient String errMessage = null;
189 * @param ccapIp - the IP of the CCAP to manage
190 * @param portNum - the port number of the CCAP to manage
192 public CcapClient(final IpAddress ccapIp, final PortNumber portNum) {
193 ipv4 = ccapIp.getIpv4Address().getValue();
194 if (portNum != null) port = portNum.getValue();
195 else port = PCMMPdpAgent.WELL_KNOWN_PDP_PORT;
196 // TODO FIXME - if this object is not null, gate processing will not work correctly
197 // TODO see - PCMMPdpReqStateMan#processReport() where the report type is success and the process is null
198 // pcmmProcess = new PCMMPdpDataProcess();
200 pcmmPdp = new PCMMPdpAgent(ipv4, port, clientType, pcmmProcess);
204 * Starts the connection to the CCAP
206 public void connect( ) {
207 logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
211 // Cannot instantiate until after pcmmPdp.connect() is called as this is where the client handle is created
212 pcmmSender = new PCMMPdpMsgSender(clientType, pcmmPdp.getClientHandle(), pcmmPdp.getSocket());
215 } catch (Exception e) {
217 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
218 errMessage = e.getMessage();
222 public void disconnect() {
223 logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
225 pcmmPdp.disconnect(new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
227 } catch (COPSException | IOException e) {
228 logger.error("CcapClient: disconnect(): {}:{} FAILED: {}", ipv4, port, e.getMessage());
232 // TODO - consider returning a new PCMMGateReq object or a future here instead of setting the ID on the old
233 // TODO - request by reference which makes the code more convoluted thus making issues more difficult to track down.
234 public Boolean sendGateSet(final PCMMGateReq gateReq) {
235 logger.info("CcapClient: sendGateSet(): {}:{} => {}", ipv4, port, gateReq);
237 pcmmSender.sendGateSet(gateReq);
239 // TODO - determine if this is the correct place to perform this operation as this currently is the
240 // TODO - place where the gate ID can be set on the gateReq object
241 // pcmmSender.handleGateReport(pcmmPdp.getSocket());
242 } catch (COPSPdpException e) {
243 logger.error("CcapClient: sendGateSet(): {}:{} => {} FAILED:", ipv4, port, gateReq, e);
245 // and save it back to the gateRequest object for gate delete later
246 gateReq.setGateID(pcmmSender.getGateID());
248 // TODO - determine why this method is always returning true???
252 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
253 logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
255 pcmmSender.sendGateDelete(gateReq);
256 } catch (COPSPdpException e) {
257 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq, e.getMessage());