blob: ce8b04be8ea7c081e5371e30244bf59a548bc134 [file] [log] [blame]
SureshBR25058b72015-08-13 13:05:06 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
SureshBR25058b72015-08-13 13:05:06 +05303 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
harikrushna-Huaweia2c7c202017-04-10 18:22:00 +053017package org.onosproject.pcep.server.impl;
SureshBR25058b72015-08-13 13:05:06 +053018
19import java.io.IOException;
20import java.net.InetSocketAddress;
21import java.net.SocketAddress;
22import java.nio.channels.ClosedChannelException;
23import java.util.Collections;
24import java.util.Date;
25import java.util.LinkedList;
26import java.util.List;
27import java.util.ListIterator;
28import java.util.concurrent.RejectedExecutionException;
29
30import org.jboss.netty.channel.Channel;
31import org.jboss.netty.channel.ChannelHandlerContext;
32import org.jboss.netty.channel.ChannelStateEvent;
33import org.jboss.netty.channel.ExceptionEvent;
34import org.jboss.netty.channel.MessageEvent;
35import org.jboss.netty.handler.timeout.IdleState;
36import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
37import org.jboss.netty.handler.timeout.IdleStateEvent;
38import org.jboss.netty.handler.timeout.IdleStateHandler;
39import org.jboss.netty.handler.timeout.ReadTimeoutException;
40import org.onlab.packet.IpAddress;
harikrushna-Huaweia2c7c202017-04-10 18:22:00 +053041import org.onosproject.pcep.server.ClientCapability;
42import org.onosproject.pcep.server.PccId;
43import org.onosproject.pcep.server.PcepCfg;
44import org.onosproject.pcep.server.driver.PcepClientDriver;
SureshBR25058b72015-08-13 13:05:06 +053045import org.onosproject.pcepio.exceptions.PcepParseException;
46import org.onosproject.pcepio.protocol.PcepError;
47import org.onosproject.pcepio.protocol.PcepErrorInfo;
48import org.onosproject.pcepio.protocol.PcepErrorMsg;
49import org.onosproject.pcepio.protocol.PcepErrorObject;
50import org.onosproject.pcepio.protocol.PcepFactory;
51import org.onosproject.pcepio.protocol.PcepMessage;
52import org.onosproject.pcepio.protocol.PcepOpenMsg;
53import org.onosproject.pcepio.protocol.PcepOpenObject;
54import org.onosproject.pcepio.protocol.PcepType;
55import org.onosproject.pcepio.protocol.PcepVersion;
Avantika-Huawei56c11842016-04-28 00:56:56 +053056import org.onosproject.pcepio.types.IPv4RouterIdOfLocalNodeSubTlv;
57import org.onosproject.pcepio.types.NodeAttributesTlv;
SureshBR25058b72015-08-13 13:05:06 +053058import org.onosproject.pcepio.types.PceccCapabilityTlv;
Priyanka B94395bf2016-05-21 18:39:46 +053059import org.onosproject.pcepio.types.SrPceCapabilityTlv;
SureshBR25058b72015-08-13 13:05:06 +053060import org.onosproject.pcepio.types.StatefulPceCapabilityTlv;
61import org.onosproject.pcepio.types.PcepErrorDetailInfo;
62import org.onosproject.pcepio.types.PcepValueType;
63import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
harikrushna-Huaweia2c7c202017-04-10 18:22:00 +053066import static org.onosproject.pcep.server.PcepSyncStatus.NOT_SYNCED;
Avantika-Huaweifc10dca2016-06-10 16:13:55 +053067
SureshBR25058b72015-08-13 13:05:06 +053068/**
69 * Channel handler deals with the pcc client connection and dispatches
70 * messages from client to the appropriate locations.
71 */
72class PcepChannelHandler extends IdleStateAwareChannelHandler {
73 static final byte DEADTIMER_MAXIMUM_VALUE = (byte) 0xFF;
74 static final byte KEEPALIVE_MULTIPLE_FOR_DEADTIMER = 4;
75 private static final Logger log = LoggerFactory.getLogger(PcepChannelHandler.class);
76 private final Controller controller;
77 private PcepClientDriver pc;
78 private PccId thispccId;
79 private Channel channel;
80 private byte sessionId = 0;
81 private byte keepAliveTime;
82 private byte deadTime;
Priyanka Bd2b28882016-04-04 16:57:04 +053083 private ClientCapability capability;
SureshBR25058b72015-08-13 13:05:06 +053084 private PcepPacketStatsImpl pcepPacketStats;
85 static final int MAX_WRONG_COUNT_PACKET = 5;
86 static final int BYTE_MASK = 0xFF;
87
88 // State needs to be volatile because the HandshakeTimeoutHandler
89 // needs to check if the handshake is complete
90 private volatile ChannelState state;
mohamedrahil00f6f262016-11-24 20:20:41 +053091 private String peerAddr;
92 private SocketAddress address;
93 private InetSocketAddress inetAddress;
SureshBR25058b72015-08-13 13:05:06 +053094 // When a pcc client with a ip addresss is found (i.e we already have a
95 // connected client with the same ip), the new client is immediately
96 // disconnected. At that point netty callsback channelDisconnected() which
97 // proceeds to cleaup client state - we need to ensure that it does not cleanup
98 // client state for the older (still connected) client
99 private volatile Boolean duplicatePccIdFound;
100
101 //Indicates the pcep version used by this pcc client
102 protected PcepVersion pcepVersion;
103 protected PcepFactory factory1;
104
105 /**
106 * Create a new unconnected PcepChannelHandler.
107 * @param controller parent controller
108 */
109 PcepChannelHandler(Controller controller) {
110 this.controller = controller;
111 this.state = ChannelState.INIT;
112 factory1 = controller.getPcepMessageFactory1();
113 duplicatePccIdFound = Boolean.FALSE;
114 pcepPacketStats = new PcepPacketStatsImpl();
115 }
116
117 /**
118 * To disconnect a PCC.
119 */
120 public void disconnectClient() {
121 pc.disconnectClient();
122 }
123
124 //*************************
125 // Channel State Machine
126 //*************************
127
SureshBR25058b72015-08-13 13:05:06 +0530128 @Override
129 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
130 channel = e.getChannel();
131 log.info("PCC connected from {}", channel.getRemoteAddress());
132
mohamedrahil00f6f262016-11-24 20:20:41 +0530133 address = channel.getRemoteAddress();
134 if (!(address instanceof InetSocketAddress)) {
135 throw new IOException("Invalid peer connection.");
136 }
137
138 inetAddress = (InetSocketAddress) address;
139 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
140
SureshBR25058b72015-08-13 13:05:06 +0530141 // Wait for open message from pcc client
142 setState(ChannelState.OPENWAIT);
mohamedrahil00f6f262016-11-24 20:20:41 +0530143 controller.peerStatus(peerAddr, PcepCfg.State.OPENWAIT.toString(), sessionId);
SureshBR25058b72015-08-13 13:05:06 +0530144 }
145
146 @Override
147 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
148 log.info("Pcc disconnected callback for pc:{}. Cleaning up ...", getClientInfoString());
mohamedrahil00f6f262016-11-24 20:20:41 +0530149 controller.peerStatus(peerAddr, PcepCfg.State.DOWN.toString(), sessionId);
150
151 channel = e.getChannel();
152 address = channel.getRemoteAddress();
153 if (!(address instanceof InetSocketAddress)) {
154 throw new IOException("Invalid peer connection.");
155 }
156
157 inetAddress = (InetSocketAddress) address;
158 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
159
SureshBR25058b72015-08-13 13:05:06 +0530160 if (thispccId != null) {
161 if (!duplicatePccIdFound) {
162 // if the disconnected client (on this ChannelHandler)
163 // was not one with a duplicate-dpid, it is safe to remove all
164 // state for it at the controller. Notice that if the disconnected
165 // client was a duplicate-ip, calling the method below would clear
166 // all state for the original client (with the same ip),
167 // which we obviously don't want.
168 log.debug("{}:removal called", getClientInfoString());
169 if (pc != null) {
170 pc.removeConnectedClient();
171 }
172 } else {
173 // A duplicate was disconnected on this ChannelHandler,
174 // this is the same client reconnecting, but the original state was
175 // not cleaned up - XXX check liveness of original ChannelHandler
176 log.debug("{}:duplicate found", getClientInfoString());
177 duplicatePccIdFound = Boolean.FALSE;
178 }
179 } else {
180 log.warn("no pccip in channelHandler registered for " + "disconnected client {}", getClientInfoString());
181 }
182 }
183
184 @Override
185 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
186 PcepErrorMsg errMsg;
187 log.info("exceptionCaught: " + e.toString());
188
189 if (e.getCause() instanceof ReadTimeoutException) {
190 if (ChannelState.OPENWAIT == state) {
191 // When ReadTimeout timer is expired in OPENWAIT state, it is considered
192 // OpenWait timer.
193 errMsg = getErrorMsg(PcepErrorDetailInfo.ERROR_TYPE_1, PcepErrorDetailInfo.ERROR_VALUE_2);
194 log.debug("Sending PCEP-ERROR message to PCC.");
mohamedrahil00f6f262016-11-24 20:20:41 +0530195 controller.peerExceptions(peerAddr, e.getCause().toString());
SureshBR25058b72015-08-13 13:05:06 +0530196 channel.write(Collections.singletonList(errMsg));
197 channel.close();
198 state = ChannelState.INIT;
199 return;
200 } else if (ChannelState.KEEPWAIT == state) {
201 // When ReadTimeout timer is expired in KEEPWAIT state, is is considered
202 // KeepWait timer.
203 errMsg = getErrorMsg(PcepErrorDetailInfo.ERROR_TYPE_1, PcepErrorDetailInfo.ERROR_VALUE_7);
204 log.debug("Sending PCEP-ERROR message to PCC.");
mohamedrahil00f6f262016-11-24 20:20:41 +0530205 controller.peerExceptions(peerAddr, e.getCause().toString());
SureshBR25058b72015-08-13 13:05:06 +0530206 channel.write(Collections.singletonList(errMsg));
207 channel.close();
208 state = ChannelState.INIT;
209 return;
210 }
211 } else if (e.getCause() instanceof ClosedChannelException) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530212 controller.peerExceptions(peerAddr, e.getCause().toString());
SureshBR25058b72015-08-13 13:05:06 +0530213 log.debug("Channel for pc {} already closed", getClientInfoString());
214 } else if (e.getCause() instanceof IOException) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530215 controller.peerExceptions(peerAddr, e.getCause().toString());
SureshBR25058b72015-08-13 13:05:06 +0530216 log.error("Disconnecting client {} due to IO Error: {}", getClientInfoString(), e.getCause().getMessage());
217 if (log.isDebugEnabled()) {
218 // still print stack trace if debug is enabled
219 log.debug("StackTrace for previous Exception: ", e.getCause());
220 }
221 channel.close();
222 } else if (e.getCause() instanceof PcepParseException) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530223 controller.peerExceptions(peerAddr, e.getCause().toString());
SureshBR25058b72015-08-13 13:05:06 +0530224 PcepParseException errMsgParse = (PcepParseException) e.getCause();
225 byte errorType = errMsgParse.getErrorType();
226 byte errorValue = errMsgParse.getErrorValue();
227
228 if ((errorType == (byte) 0x0) && (errorValue == (byte) 0x0)) {
229 processUnknownMsg();
230 } else {
231 errMsg = getErrorMsg(errorType, errorValue);
232 log.debug("Sending PCEP-ERROR message to PCC.");
233 channel.write(Collections.singletonList(errMsg));
234 }
235 } else if (e.getCause() instanceof RejectedExecutionException) {
236 log.warn("Could not process message: queue full");
mohamedrahil00f6f262016-11-24 20:20:41 +0530237 controller.peerExceptions(peerAddr, e.getCause().toString());
SureshBR25058b72015-08-13 13:05:06 +0530238 } else {
239 log.error("Error while processing message from client " + getClientInfoString() + "state " + this.state);
mohamedrahil00f6f262016-11-24 20:20:41 +0530240 controller.peerExceptions(peerAddr, e.getCause().toString());
SureshBR25058b72015-08-13 13:05:06 +0530241 channel.close();
242 }
243 }
244
245 @Override
246 public String toString() {
247 return getClientInfoString();
248 }
249
250 @Override
251 public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
252 if (!isHandshakeComplete()) {
253 return;
254 }
255
256 if (e.getState() == IdleState.READER_IDLE) {
257 // When no message is received on channel for read timeout, then close
258 // the channel
259 log.info("Disconnecting client {} due to read timeout", getClientInfoString());
260 ctx.getChannel().close();
261 } else if (e.getState() == IdleState.WRITER_IDLE) {
262 // Send keep alive message
263 log.debug("Sending keep alive message due to IdleState timeout " + pc.toString());
264 pc.sendMessage(Collections.singletonList(pc.factory().buildKeepaliveMsg().build()));
265 }
266 }
267
268 @Override
269 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
270 if (e.getMessage() instanceof List) {
271 @SuppressWarnings("unchecked")
272 List<PcepMessage> msglist = (List<PcepMessage>) e.getMessage();
273 for (PcepMessage pm : msglist) {
274 // Do the actual packet processing
275 state.processPcepMessage(this, pm);
276 }
277 } else {
278 state.processPcepMessage(this, (PcepMessage) e.getMessage());
279 }
280 }
281
282 /**
SureshBR25058b72015-08-13 13:05:06 +0530283 * Is this a state in which the handshake has completed.
284 *
285 * @return true if the handshake is complete
286 */
287 public boolean isHandshakeComplete() {
288 return this.state.isHandshakeComplete();
289 }
290
291 /**
mohamedrahil00f6f262016-11-24 20:20:41 +0530292 * To set the handshake status.
293 *
294 * @param handshakeComplete value is handshake status
295 */
296 public void setHandshakeComplete(boolean handshakeComplete) {
297 this.state.setHandshakeComplete(handshakeComplete);
298 }
299
300 /**
SureshBR25058b72015-08-13 13:05:06 +0530301 * To handle the pcep message.
302 *
303 * @param m pcep message
304 */
305 private void dispatchMessage(PcepMessage m) {
306 pc.handleMessage(m);
307 }
308
309 /**
Avantika-Huaweife44ea62016-05-27 19:21:24 +0530310 * Adds PCEP device configuration with capabilities once session is established.
Priyanka B94395bf2016-05-21 18:39:46 +0530311 */
312 private void addNode() {
313 pc.addNode(pc);
314 }
315
316 /**
Avantika-Huaweife44ea62016-05-27 19:21:24 +0530317 * Deletes PCEP device configuration when session is disconnected.
Priyanka B94395bf2016-05-21 18:39:46 +0530318 */
319 private void deleteNode() {
320 pc.deleteNode(pc.getPccId());
321 }
322
323 /**
SureshBR25058b72015-08-13 13:05:06 +0530324 * Return a string describing this client based on the already available
325 * information (ip address and/or remote socket).
326 *
327 * @return display string
328 */
329 private String getClientInfoString() {
330 if (pc != null) {
331 return pc.toString();
332 }
333 String channelString;
334 if (channel == null || channel.getRemoteAddress() == null) {
335 channelString = "?";
336 } else {
337 channelString = channel.getRemoteAddress().toString();
338 }
339 String pccIpString;
340 // TODO : implement functionality to get pcc id string
341 pccIpString = "?";
342 return String.format("[%s PCCIP[%s]]", channelString, pccIpString);
343 }
344
345 /**
346 * Update the channels state. Only called from the state machine.
347 *
348 * @param state
349 */
350 private void setState(ChannelState state) {
351 this.state = state;
352 }
353
354 /**
355 * Send handshake open message.
356 *
357 * @throws IOException,PcepParseException
358 */
359 private void sendHandshakeOpenMessage() throws IOException, PcepParseException {
360 PcepOpenObject pcepOpenobj = factory1.buildOpenObject()
361 .setSessionId(sessionId)
362 .setKeepAliveTime(keepAliveTime)
363 .setDeadTime(deadTime)
364 .build();
365 PcepMessage msg = factory1.buildOpenMsg()
366 .setPcepOpenObj(pcepOpenobj)
367 .build();
368 log.debug("Sending OPEN message to {}", channel.getRemoteAddress());
369 channel.write(Collections.singletonList(msg));
370 }
371
Priyanka Bd2b28882016-04-04 16:57:04 +0530372 //Capability negotiation
373 private void capabilityNegotiation(PcepOpenMsg pOpenmsg) {
SureshBR25058b72015-08-13 13:05:06 +0530374 LinkedList<PcepValueType> tlvList = pOpenmsg.getPcepOpenObject().getOptionalTlv();
Priyanka Bd2b28882016-04-04 16:57:04 +0530375 boolean pceccCapability = false;
376 boolean statefulPceCapability = false;
377 boolean pcInstantiationCapability = false;
Priyanka B94395bf2016-05-21 18:39:46 +0530378 boolean labelStackCapability = false;
379 boolean srCapability = false;
SureshBR25058b72015-08-13 13:05:06 +0530380
381 ListIterator<PcepValueType> listIterator = tlvList.listIterator();
382 while (listIterator.hasNext()) {
383 PcepValueType tlv = listIterator.next();
384
385 switch (tlv.getType()) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530386 case PceccCapabilityTlv.TYPE:
387 pceccCapability = true;
388 if (((PceccCapabilityTlv) tlv).sBit()) {
389 labelStackCapability = true;
390 }
391 break;
392 case StatefulPceCapabilityTlv.TYPE:
393 statefulPceCapability = true;
394 StatefulPceCapabilityTlv stetefulPcCapTlv = (StatefulPceCapabilityTlv) tlv;
395 if (stetefulPcCapTlv.getIFlag()) {
396 pcInstantiationCapability = true;
397 }
398 break;
399 case SrPceCapabilityTlv.TYPE:
400 srCapability = true;
401 break;
402 default:
403 continue;
SureshBR25058b72015-08-13 13:05:06 +0530404 }
405 }
Priyanka B94395bf2016-05-21 18:39:46 +0530406 this.capability = new ClientCapability(pceccCapability, statefulPceCapability, pcInstantiationCapability,
407 labelStackCapability, srCapability);
SureshBR25058b72015-08-13 13:05:06 +0530408 }
409
410 /**
411 * Send keep alive message.
412 *
mohamedrahil00f6f262016-11-24 20:20:41 +0530413 * @throws IOException when channel is disconnected
SureshBR25058b72015-08-13 13:05:06 +0530414 * @throws PcepParseException while building keep alive message
415 */
416 private void sendKeepAliveMessage() throws IOException, PcepParseException {
417 PcepMessage msg = factory1.buildKeepaliveMsg().build();
418 log.debug("Sending KEEPALIVE message to {}", channel.getRemoteAddress());
419 channel.write(Collections.singletonList(msg));
420 }
421
422 /**
423 * Send error message and close channel with pcc.
424 */
425 private void sendErrMsgAndCloseChannel() {
426 // TODO send error message
Priyanka B94395bf2016-05-21 18:39:46 +0530427 //Remove PCEP device from topology
428 deleteNode();
SureshBR25058b72015-08-13 13:05:06 +0530429 channel.close();
430 }
431
432 /**
433 * Send error message when an invalid message is received.
434 *
435 * @throws PcepParseException while building error message
436 */
437 private void sendErrMsgForInvalidMsg() throws PcepParseException {
438 byte errorType = 0x02;
439 byte errorValue = 0x00;
440 PcepErrorMsg errMsg = getErrorMsg(errorType, errorValue);
441 channel.write(Collections.singletonList(errMsg));
442 }
443
444 /**
445 * Builds pcep error message based on error value and error type.
446 *
447 * @param errorType pcep error type
448 * @param errorValue pcep error value
449 * @return pcep error message
450 * @throws PcepParseException while bulding error message
451 */
452 public PcepErrorMsg getErrorMsg(byte errorType, byte errorValue) throws PcepParseException {
Sho SHIMIZU9b8274c2015-09-04 15:54:24 -0700453 LinkedList<PcepErrorObject> llerrObj = new LinkedList<>();
SureshBR25058b72015-08-13 13:05:06 +0530454 PcepErrorMsg errMsg;
455
456 PcepErrorObject errObj = factory1.buildPcepErrorObject()
457 .setErrorValue(errorValue)
458 .setErrorType(errorType)
459 .build();
460
461 llerrObj.add(errObj);
462
mohamedrahil00f6f262016-11-24 20:20:41 +0530463 //If Error caught in other than Openmessage
464 LinkedList<PcepError> llPcepErr = new LinkedList<>();
SureshBR25058b72015-08-13 13:05:06 +0530465
mohamedrahil00f6f262016-11-24 20:20:41 +0530466 PcepError pcepErr = factory1.buildPcepError()
467 .setErrorObjList(llerrObj)
468 .build();
SureshBR25058b72015-08-13 13:05:06 +0530469
mohamedrahil00f6f262016-11-24 20:20:41 +0530470 llPcepErr.add(pcepErr);
SureshBR25058b72015-08-13 13:05:06 +0530471
mohamedrahil00f6f262016-11-24 20:20:41 +0530472 PcepErrorInfo errInfo = factory1.buildPcepErrorInfo()
473 .setPcepErrorList(llPcepErr)
474 .build();
SureshBR25058b72015-08-13 13:05:06 +0530475
mohamedrahil00f6f262016-11-24 20:20:41 +0530476 errMsg = factory1.buildPcepErrorMsg()
477 .setPcepErrorInfo(errInfo)
478 .build();
SureshBR25058b72015-08-13 13:05:06 +0530479 return errMsg;
480 }
481
482 /**
483 * Process unknown pcep message received.
484 *
485 * @throws PcepParseException while building pcep error message
486 */
487 public void processUnknownMsg() throws PcepParseException {
Ray Milkey7b332f12018-01-19 09:59:16 -0800488 Date now = new Date();
SureshBR25058b72015-08-13 13:05:06 +0530489 if (pcepPacketStats.wrongPacketCount() == 0) {
SureshBR25058b72015-08-13 13:05:06 +0530490 pcepPacketStats.setTime(now.getTime());
491 pcepPacketStats.addWrongPacket();
492 sendErrMsgForInvalidMsg();
493 }
494
495 if (pcepPacketStats.wrongPacketCount() > 1) {
496 Date lastest = new Date();
497 pcepPacketStats.addWrongPacket();
498 //converting to seconds
499 if (((lastest.getTime() - pcepPacketStats.getTime()) / 1000) > 60) {
500 now = lastest;
501 pcepPacketStats.setTime(now.getTime());
502 pcepPacketStats.resetWrongPacket();
503 pcepPacketStats.addWrongPacket();
504 } else if (((int) (lastest.getTime() - now.getTime()) / 1000) < 60) {
505 if (MAX_WRONG_COUNT_PACKET <= pcepPacketStats.wrongPacketCount()) {
506 //reset once wrong packet count reaches MAX_WRONG_COUNT_PACKET
507 pcepPacketStats.resetWrongPacket();
508 // max wrong packets received send error message and close the session
509 sendErrMsgAndCloseChannel();
510 }
511 }
512 }
513 }
mohamedrahil00f6f262016-11-24 20:20:41 +0530514
515 /**
516 * The state machine for handling the client/channel state. All state
517 * transitions should happen from within the state machine (and not from other
518 * parts of the code)
519 */
520 enum ChannelState {
521 /**
522 * Initial state before channel is connected.
523 */
524 INIT(false) {
525
526 },
527 /**
528 * Once the session is established, wait for open message.
529 */
530 OPENWAIT(false) {
531 @Override
532 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
533
534 log.info("Message received in OPEN WAIT State");
535
536 //check for open message
537 if (m.getType() != PcepType.OPEN) {
538 // When the message type is not open message increment the wrong packet statistics
539 h.processUnknownMsg();
540 log.debug("Message is not OPEN message");
541 } else {
542
543 h.pcepPacketStats.addInPacket();
544 PcepOpenMsg pOpenmsg = (PcepOpenMsg) m;
545 //Do Capability negotiation.
546 h.capabilityNegotiation(pOpenmsg);
547 log.debug("Sending handshake OPEN message");
548 h.sessionId = pOpenmsg.getPcepOpenObject().getSessionId();
549 h.pcepVersion = pOpenmsg.getPcepOpenObject().getVersion();
550
551 //setting keepalive and deadTimer
552 byte yKeepalive = pOpenmsg.getPcepOpenObject().getKeepAliveTime();
553 byte yDeadTimer = pOpenmsg.getPcepOpenObject().getDeadTime();
554 h.keepAliveTime = yKeepalive;
555 if (yKeepalive < yDeadTimer) {
556 h.deadTime = yDeadTimer;
557 } else {
558 if (DEADTIMER_MAXIMUM_VALUE > (yKeepalive * KEEPALIVE_MULTIPLE_FOR_DEADTIMER)) {
559 h.deadTime = (byte) (yKeepalive * KEEPALIVE_MULTIPLE_FOR_DEADTIMER);
560 } else {
561 h.deadTime = DEADTIMER_MAXIMUM_VALUE;
562 }
563 }
564
565 /*
566 * If MPLS LSR id and PCEP session socket IP addresses are not same,
567 * the MPLS LSR id will be encoded in separate TLV.
568 * We always maintain session information based on LSR ids.
569 * The socket IP is stored in channel.
570 */
571 LinkedList<PcepValueType> optionalTlvs = pOpenmsg.getPcepOpenObject().getOptionalTlv();
572 if (optionalTlvs != null) {
573 for (PcepValueType optionalTlv : optionalTlvs) {
574 if (optionalTlv instanceof NodeAttributesTlv) {
575 List<PcepValueType> subTlvs = ((NodeAttributesTlv) optionalTlv)
576 .getllNodeAttributesSubTLVs();
577 if (subTlvs == null) {
578 break;
579 }
580 for (PcepValueType subTlv : subTlvs) {
581 if (subTlv instanceof IPv4RouterIdOfLocalNodeSubTlv) {
582 h.thispccId = PccId.pccId(IpAddress
583 .valueOf(((IPv4RouterIdOfLocalNodeSubTlv) subTlv).getInt()));
584 break;
585 }
586 }
587 break;
588 }
589 }
590 }
591
592 if (h.thispccId == null) {
593 final SocketAddress address = h.channel.getRemoteAddress();
594 if (!(address instanceof InetSocketAddress)) {
595 throw new IOException("Invalid client connection. Pcc is indentifed based on IP");
596 }
597
598 final InetSocketAddress inetAddress = (InetSocketAddress) address;
599 h.thispccId = PccId.pccId(IpAddress.valueOf(inetAddress.getAddress()));
600 }
601
602 h.sendHandshakeOpenMessage();
603 h.pcepPacketStats.addOutPacket();
604 h.setState(KEEPWAIT);
605 h.controller.peerStatus(h.peerAddr.toString(), PcepCfg.State.KEEPWAIT.toString(), h.sessionId);
606 }
607 }
608 },
609 /**
610 * Once the open messages are exchanged, wait for keep alive message.
611 */
612 KEEPWAIT(false) {
613 @Override
614 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
615 log.info("Message received in KEEPWAIT state");
616 //check for keep alive message
617 if (m.getType() != PcepType.KEEP_ALIVE) {
618 // When the message type is not keep alive message increment the wrong packet statistics
619 h.processUnknownMsg();
620 log.error("Message is not KEEPALIVE message");
621 } else {
622 // Set the client connected status
623 h.pcepPacketStats.addInPacket();
624 log.debug("sending keep alive message in KEEPWAIT state");
625 h.pc = h.controller.getPcepClientInstance(h.thispccId, h.sessionId, h.pcepVersion,
626 h.pcepPacketStats);
627 //Get pc instance and set capabilities
628 h.pc.setCapability(h.capability);
629
630 // Initilialize DB sync status.
631 h.pc.setLspDbSyncStatus(NOT_SYNCED);
632 h.pc.setLabelDbSyncStatus(NOT_SYNCED);
633
634 // set the status of pcc as connected
635 h.pc.setConnected(true);
636 h.pc.setChannel(h.channel);
637
638 // set any other specific parameters to the pcc
639 h.pc.setPcVersion(h.pcepVersion);
640 h.pc.setPcSessionId(h.sessionId);
641 h.pc.setPcKeepAliveTime(h.keepAliveTime);
642 h.pc.setPcDeadTime(h.deadTime);
643 int keepAliveTimer = h.keepAliveTime & BYTE_MASK;
644 int deadTimer = h.deadTime & BYTE_MASK;
645 if (0 == h.keepAliveTime) {
646 h.deadTime = 0;
647 }
648 // handle keep alive and dead time
649 if (keepAliveTimer != PcepPipelineFactory.DEFAULT_KEEP_ALIVE_TIME
650 || deadTimer != PcepPipelineFactory.DEFAULT_DEAD_TIME) {
651
652 h.channel.getPipeline().replace("idle", "idle",
653 new IdleStateHandler(PcepPipelineFactory.TIMER, deadTimer, keepAliveTimer, 0));
654 }
655 log.debug("Dead timer : " + deadTimer);
656 log.debug("Keep alive time : " + keepAliveTimer);
657
658 //set the state handshake completion.
659
660 h.sendKeepAliveMessage();
661 h.pcepPacketStats.addOutPacket();
662 h.setHandshakeComplete(true);
663
664 if (!h.pc.connectClient()) {
665 disconnectDuplicate(h);
666 } else {
667 h.setState(ESTABLISHED);
668 h.controller.peerStatus(h.peerAddr.toString(), PcepCfg.State.ESTABLISHED.toString(), h.sessionId);
669 //Session is established, add a network configuration with LSR id and device capabilities.
670 h.addNode();
671 }
672 }
673 }
674 },
675 /**
676 * Once the keep alive messages are exchanged, the state is established.
677 */
678 ESTABLISHED(true) {
679 @Override
680 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
681
682 //h.channel.getPipeline().remove("waittimeout");
683 log.debug("Message received in established state " + m.getType());
684 //dispatch the message
685 h.dispatchMessage(m);
686 }
687 };
688 private boolean handshakeComplete;
689
690 ChannelState(boolean handshakeComplete) {
691 this.handshakeComplete = handshakeComplete;
692 }
693
694 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
695 // do nothing
696 }
697
698 /**
699 * Is this a state in which the handshake has completed.
700 *
701 * @return true if the handshake is complete
702 */
703 public boolean isHandshakeComplete() {
704 return this.handshakeComplete;
705 }
706
707 /**
708 * Sets handshake complete status.
709 *
710 * @param handshakeComplete status of handshake
711 */
Ray Milkey928644f2018-02-02 16:03:57 -0800712 private void setHandshakeComplete(boolean handshakeComplete) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530713 this.handshakeComplete = handshakeComplete;
714 }
715
716 protected void disconnectDuplicate(PcepChannelHandler h) {
717 log.error("Duplicated Pcc IP or incompleted cleanup - " + "disconnecting channel {}",
718 h.getClientInfoString());
719 h.duplicatePccIdFound = Boolean.TRUE;
720 h.channel.disconnect();
721 }
722
723 }
SureshBR25058b72015-08-13 13:05:06 +0530724}