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.Ipv4Address;
6 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
7 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceClassName;
8 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceFlowDirection;
9 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.Ccaps;
10 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.Gates;
11 import org.pcmm.PCMMPdpAgent;
12 import org.pcmm.PCMMPdpDataProcess;
13 import org.pcmm.PCMMPdpMsgSender;
14 import org.pcmm.gates.impl.PCMMGateReq;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17 import org.umu.cops.prpdp.COPSPdpException;
18 import org.umu.cops.stack.COPSError;
19 import org.umu.cops.stack.COPSError.ErrorTypes;
20 import org.umu.cops.stack.COPSException;
22 import javax.annotation.concurrent.ThreadSafe;
23 import java.io.IOException;
24 import java.net.InetAddress;
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 Ccaps 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 Ccaps 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(), portNum.getValue());
51 public void disconect() {
52 ccapClient.disconnect();
55 // TODO - try and change the return to something other than a String to be parsed to determine success
56 public String addCcap() {
58 if (ccapClient.isConnected) {
59 logger.info("Connected to CCAP with ID - " + ccap.getCcapId());
60 return String.format("200 OK - CCAP %s connected @ %s:%d", ccap.getCcapId(),
61 ipAddr.getIpv4Address().getValue(), portNum.getValue());
63 return String.format("404 Not Found - CCAP %s failed to connect @ %s:%d - %s",
65 ipAddr.getIpv4Address().getValue(), portNum.getValue(), ccapClient.errMessage);
69 // TODO - Consider creating an object to return that contains a success flag, message, and gate ID or gate object
70 // TODO FIXME - the gate appears to be getting set as per restconf but I am not seeing the proper logging occurring
71 public String sendGateSet(final String gatePathStr, final InetAddress subId, final Gates 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.build(ccap.getAmId());
77 gateBuilder.build(subId);
78 // force gateSpec.Direction to align with SCN direction
79 final ServiceClassName scn = qosGate.getTrafficProfile().getServiceClassName();
81 gateBuilder.build(qosGate.getGateSpec(), scnDir);
84 gateBuilder.build(qosGate.getGateSpec(), null);
86 gateBuilder.build(qosGate.getTrafficProfile());
88 // pick a classifier type (only one for now)
89 if (qosGate.getClassifier() != null) {
90 gateBuilder.build(qosGate.getClassifier());
91 } else if (qosGate.getExtClassifier() != null) {
92 gateBuilder.build(qosGate.getExtClassifier());
93 } else if (qosGate.getIpv6Classifier() != null) {
94 gateBuilder.build(qosGate.getIpv6Classifier());
96 // assemble the final gate request
97 final PCMMGateReq gateReq = gateBuilder.getGateReq();
100 gateRequests.put(gatePathStr, gateReq);
101 // and send it to the CCAP
102 ccapClient.sendGateSet(gateReq);
103 // and wait for the COPS response to complete processing gate request
105 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
106 // TODO - handle this synchronization.
107 // TODO - if not changing this, may want to make this timeout configurable
108 synchronized(gateReq) {
109 logger.info("Waiting 1000ms for gate request to be updated");
111 logger.debug("Gate request error - " + gateReq.getError());
112 logger.debug("Gate request ID - " + gateReq.getGateID());
114 } catch (Exception e) {
115 logger.error("PCMMService: sendGateSet(): gate response timeout exceeded for "
116 + gatePathStr + '/' + gateReq, e);
117 return String.format("408 Request Timeout - gate response timeout exceeded for %s/%s",
118 ccap.getCcapId(), gatePathStr);
120 if (gateReq.getError() != null) {
121 logger.error("PCMMService: sendGateSet(): returned error: {}",
122 gateReq.getError().toString());
123 return String.format("404 Not Found - sendGateSet for %s/%s returned error - %s",
124 ccap.getCcapId(), gatePathStr, gateReq.getError().toString());
126 if (gateReq.getGateID() != null) {
127 logger.info(String.format("PCMMService: sendGateSet(): returned GateId %08x: ",
128 gateReq.getGateID().getGateID()));
129 return String.format("200 OK - sendGateSet for %s/%s returned GateId %08x",
130 ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID());
132 logger.info("PCMMService: sendGateSet(): no gateId returned:");
133 return String.format("404 Not Found - sendGateSet for %s/%s no gateId returned",
134 ccap.getCcapId(), gatePathStr);
139 public Boolean sendGateDelete(final String gatePathStr) {
140 logger.info("sendGateDelete() - " + ccap);
141 // recover the original gate request
142 final PCMMGateReq gateReq = gateRequests.remove(gatePathStr);
143 if (gateReq != null) {
144 ccapClient.sendGateDelete(gateReq);
145 // and wait for the response to complete
147 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
148 // TODO - handle this synchronization.
149 synchronized(gateReq) {
152 } catch (InterruptedException e) {
153 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}",
154 gatePathStr, gateReq);
156 if (gateReq.getError() != null) {
157 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
160 if (gateReq.getGateID() != null) {
161 logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ", gateReq.getGateID().getGateID()));
163 logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
172 private String getIpAddressStr(final IpAddress ipAddress) {
173 final Ipv4Address ipv4 = ipAddress.getIpv4Address();
175 return ipv4.getValue();
177 return ipAddress.getIpv6Address().getValue();
182 * Used to interface with a CCAP (including CMTSs)
184 protected class CcapClient {
185 public final PCMMPdpDataProcess pcmmProcess;
186 public final PCMMPdpAgent pcmmPdp;
188 private final String ipv4;
189 private final Integer port;
191 // Needs to be initialized in connect() method else would be final
192 protected transient PCMMPdpMsgSender pcmmSender;
194 private transient Boolean isConnected = false;
195 private transient String errMessage = null;
199 * @param ccapIp - the IP of the CCAP to manage
200 * @param portNum - the port number of the CCAP to manage
202 public CcapClient(final IpAddress ccapIp, final PortNumber portNum) {
203 ipv4 = ccapIp.getIpv4Address().getValue();
204 if (portNum != null) port = portNum.getValue();
205 else port = PCMMPdpAgent.WELL_KNOWN_PDP_PORT;
206 // TODO FIXME - if this object is not null, gate processing will not work correctly
207 // TODO see - PCMMPdpReqStateMan#processReport() where the report type is success and the process is null
208 // pcmmProcess = new PCMMPdpDataProcess();
210 pcmmPdp = new PCMMPdpAgent(clientType, ipv4, port, pcmmProcess);
214 * Starts the connection to the CCAP
216 public void connect( ) {
217 logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
221 // Cannot instantiate until after pcmmPdp.connect() is called as this is where the client handle is created
222 pcmmSender = new PCMMPdpMsgSender(clientType, pcmmPdp.getClientHandle(), pcmmPdp.getSocket());
225 } catch (Exception e) {
227 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
228 errMessage = e.getMessage();
232 public void disconnect() {
233 logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
235 pcmmPdp.disconnect(pcmmPdp.getPepIdString(), new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
237 } catch (COPSException | IOException e) {
238 logger.error("CcapClient: disconnect(): {}:{} FAILED: {}", ipv4, port, e.getMessage());
242 // TODO - consider returning a new PCMMGateReq object or a future here instead of setting the ID on the old
243 // TODO - request by reference which makes the code more convoluted thus making issues more difficult to track down.
244 public Boolean sendGateSet(final PCMMGateReq gateReq) {
245 logger.info("CcapClient: sendGateSet(): {}:{} => {}", ipv4, port, gateReq);
247 pcmmSender.sendGateSet(gateReq);
249 // TODO - determine if this is the correct place to perform this operation as this currently is the
250 // TODO - place where the gate ID can be set on the gateReq object
251 // pcmmSender.handleGateReport(pcmmPdp.getSocket());
252 } catch (COPSPdpException e) {
253 logger.error("CcapClient: sendGateSet(): {}:{} => {} FAILED:", ipv4, port, gateReq, e);
255 // and save it back to the gateRequest object for gate delete later
256 gateReq.setGateID(pcmmSender.getGateID());
258 // TODO - determine why this method is always returning true???
262 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
263 logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
265 pcmmSender.sendGateDelete(gateReq);
266 } catch (COPSPdpException e) {
267 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq, e.getMessage());