Updated model yang file to use recommended practices found on wiki, then updated...
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / PCMMService.java
1 /*
2  * (c) 2015 Cable Television Laboratories, Inc.  All rights reserved.
3  */
4
5 package org.opendaylight.controller.packetcable.provider;
6
7 import com.google.common.collect.Maps;
8 import java.net.InetAddress;
9 import java.util.Map;
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;
26
27 /**
28  * Class responsible for managing the gates for a single CCAP.
29  */
30 @ThreadSafe
31 public class PCMMService {
32         private Logger logger = LoggerFactory.getLogger(PCMMService.class);
33
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();
39
40         private final short clientType;
41
42         public PCMMService(final short clientType, final Ccap ccap) {
43                 this.clientType = clientType;
44                 this.ccap = ccap;
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(),
49                                 portNum.getValue());
50         }
51
52         public void disconect() {
53                 ccapClient.disconnect();
54         }
55
56         // TODO - try and change the return to something other than a String to be parsed to determine success
57         public String addCcap() {
58                 ccapClient.connect();
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());
63                 } else {
64                         return String.format("404 Not Found - CCAP %s failed to connect @ %s:%d - %s",
65                                         ccap.getCcapId(),
66                                         ipAddr.getIpv4Address().getValue(), portNum.getValue(), ccapClient.errMessage);
67                 }
68         }
69
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();
80                 if (scn != null) {
81                         gateBuilder.setGateSpec(qosGate.getGateSpec(), scnDir);
82                 } else {
83                         // not an SCN gate
84                         gateBuilder.setGateSpec(qosGate.getGateSpec(), null);
85                 }
86                 gateBuilder.setTrafficProfile(qosGate.getTrafficProfile());
87
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());
95                 }
96                 // assemble the final gate request
97                 final PCMMGateReq gateReq = gateBuilder.build();
98
99                 if (gateRequests.get(gatePathStr) == null) {
100                         // and remember it
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
105                         try {
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");
111                                         gateReq.wait(5000);
112                                         logger.debug("Gate request error - " + gateReq.getError());
113                                         logger.debug("Gate request ID - " + gateReq.getGateID());
114                                 }
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);
120                         }
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());
126                         } else {
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());
132                                 } else {
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);
136                                 }
137                         }
138                 } else {
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);
142                 }
143         }
144
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
152                         try {
153                                 // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
154                                 // TODO - handle this synchronization.
155                                 synchronized(gateReq) {
156                                         gateReq.wait(1000);
157                                 }
158                         } catch (InterruptedException e) {
159                                 logger.error("PCMMService: sendGateDelete(): gate response timeout exceeded for {}/{}",
160                                                 gatePathStr, gateReq);
161                         }
162                         if (gateReq.getError() != null) {
163                                 logger.warn("PCMMService: sendGateDelete(): returned error: {}", gateReq.getError().toString());
164                                 return false;
165                         } else {
166                                 if (gateReq.getGateID() != null) {
167                                         logger.info(String.format("PCMMService: sendGateDelete(): deleted GateId %08x: ", gateReq.getGateID().getGateID()));
168                                 } else {
169                                         logger.error("PCMMService: sendGateDelete(): deleted but no gateId returned");
170                                 }
171                                 return true;
172                         }
173                 } else {
174                         logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
175                         return false;
176                 }
177         }
178
179         /**
180          * Used to interface with a CCAP (including CMTSs)
181          */
182         protected class CcapClient {
183                 public final PCMMPdpDataProcess pcmmProcess;
184                 public final PCMMPdpAgent pcmmPdp;
185
186                 private final String ipv4;
187                 private final Integer port;
188
189                 // Needs to be initialized in connect() method else would be final
190                 protected transient PCMMPdpMsgSender pcmmSender;
191
192                 private transient Boolean isConnected = false;
193                 private transient String errMessage = null;
194
195                 /**
196                  * Constructor
197                  * @param ccapIp - the IP of the CCAP to manage
198                  * @param portNum - the port number of the CCAP to manage
199                  */
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();
207                         pcmmProcess = null;
208                         pcmmPdp = new PCMMPdpAgent(ipv4, port, clientType, pcmmProcess);
209                 }
210
211                 /**
212                  * Starts the connection to the CCAP
213                  */
214                 public void connect( ) {
215                         logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
216                         try  {
217                                 pcmmPdp.connect();
218
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());
221
222                                 isConnected = true;
223                         } catch (Exception e) {
224                                 isConnected = false;
225                                 logger.error("Failed to connect to host: " + ipv4 + " port: " + port, e);
226                                 errMessage = e.getMessage();
227                         }
228                 }
229
230                 public void disconnect() {
231                         logger.info("CcapClient: disconnect(): {}:{}", ipv4, port);
232                         pcmmPdp.disconnect(new COPSError(ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA));
233                         isConnected = false;
234                 }
235
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);
240                         try {
241                                 pcmmSender.sendGateSet(gateReq);
242
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);
248                         }
249                         // and save it back to the gateRequest object for gate delete later
250                         gateReq.setGateID(pcmmSender.getGateID());
251
252                         // TODO - determine why this method is always returning true???
253                         return true;
254                 }
255
256                 public Boolean sendGateDelete(final PCMMGateReq gateReq) {
257                         logger.info("CcapClient: sendGateDelete(): {}:{} => {}", ipv4, port, gateReq);
258                         try {
259                                 pcmmSender.sendGateDelete(gateReq);
260                         } catch (COPSPdpException e) {
261                                 logger.error("CcapClient: sendGateDelete(): {}:{} => {} FAILED: {}", ipv4, port, gateReq, e.getMessage());
262                         }
263                         return true;
264                 }
265         }
266 }
267