blob: d2523f528c8db775938425890e2979d8dddd97e4 [file] [log] [blame]
SureshBR25058b72015-08-13 13:05:06 +05301/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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
17package org.onosproject.pcep.controller.impl;
18
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;
Priyanka Bd2b28882016-04-04 16:57:04 +053041import org.onosproject.pcep.controller.ClientCapability;
SureshBR25058b72015-08-13 13:05:06 +053042import org.onosproject.pcep.controller.PccId;
43import org.onosproject.pcep.controller.driver.PcepClientDriver;
44import org.onosproject.pcepio.exceptions.PcepParseException;
45import org.onosproject.pcepio.protocol.PcepError;
46import org.onosproject.pcepio.protocol.PcepErrorInfo;
47import org.onosproject.pcepio.protocol.PcepErrorMsg;
48import org.onosproject.pcepio.protocol.PcepErrorObject;
49import org.onosproject.pcepio.protocol.PcepFactory;
50import org.onosproject.pcepio.protocol.PcepMessage;
51import org.onosproject.pcepio.protocol.PcepOpenMsg;
52import org.onosproject.pcepio.protocol.PcepOpenObject;
53import org.onosproject.pcepio.protocol.PcepType;
54import org.onosproject.pcepio.protocol.PcepVersion;
Avantika-Huawei56c11842016-04-28 00:56:56 +053055import org.onosproject.pcepio.types.IPv4RouterIdOfLocalNodeSubTlv;
56import org.onosproject.pcepio.types.NodeAttributesTlv;
SureshBR25058b72015-08-13 13:05:06 +053057import org.onosproject.pcepio.types.PceccCapabilityTlv;
Priyanka B94395bf2016-05-21 18:39:46 +053058import org.onosproject.pcepio.types.SrPceCapabilityTlv;
SureshBR25058b72015-08-13 13:05:06 +053059import org.onosproject.pcepio.types.StatefulPceCapabilityTlv;
60import org.onosproject.pcepio.types.PcepErrorDetailInfo;
61import org.onosproject.pcepio.types.PcepValueType;
62import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Avantika-Huaweifc10dca2016-06-10 16:13:55 +053065import static org.onosproject.pcep.controller.PcepSyncStatus.NOT_SYNCED;
66
SureshBR25058b72015-08-13 13:05:06 +053067/**
68 * Channel handler deals with the pcc client connection and dispatches
69 * messages from client to the appropriate locations.
70 */
71class PcepChannelHandler extends IdleStateAwareChannelHandler {
72 static final byte DEADTIMER_MAXIMUM_VALUE = (byte) 0xFF;
73 static final byte KEEPALIVE_MULTIPLE_FOR_DEADTIMER = 4;
74 private static final Logger log = LoggerFactory.getLogger(PcepChannelHandler.class);
75 private final Controller controller;
76 private PcepClientDriver pc;
77 private PccId thispccId;
78 private Channel channel;
79 private byte sessionId = 0;
80 private byte keepAliveTime;
81 private byte deadTime;
Priyanka Bd2b28882016-04-04 16:57:04 +053082 private ClientCapability capability;
SureshBR25058b72015-08-13 13:05:06 +053083 private PcepPacketStatsImpl pcepPacketStats;
84 static final int MAX_WRONG_COUNT_PACKET = 5;
85 static final int BYTE_MASK = 0xFF;
86
87 // State needs to be volatile because the HandshakeTimeoutHandler
88 // needs to check if the handshake is complete
89 private volatile ChannelState state;
90
91 // When a pcc client with a ip addresss is found (i.e we already have a
92 // connected client with the same ip), the new client is immediately
93 // disconnected. At that point netty callsback channelDisconnected() which
94 // proceeds to cleaup client state - we need to ensure that it does not cleanup
95 // client state for the older (still connected) client
96 private volatile Boolean duplicatePccIdFound;
97
98 //Indicates the pcep version used by this pcc client
99 protected PcepVersion pcepVersion;
100 protected PcepFactory factory1;
101
102 /**
103 * Create a new unconnected PcepChannelHandler.
104 * @param controller parent controller
105 */
106 PcepChannelHandler(Controller controller) {
107 this.controller = controller;
108 this.state = ChannelState.INIT;
109 factory1 = controller.getPcepMessageFactory1();
110 duplicatePccIdFound = Boolean.FALSE;
111 pcepPacketStats = new PcepPacketStatsImpl();
112 }
113
114 /**
115 * To disconnect a PCC.
116 */
117 public void disconnectClient() {
118 pc.disconnectClient();
119 }
120
121 //*************************
122 // Channel State Machine
123 //*************************
124
125 /**
126 * The state machine for handling the client/channel state. All state
127 * transitions should happen from within the state machine (and not from other
128 * parts of the code)
129 */
130 enum ChannelState {
131 /**
132 * Initial state before channel is connected.
133 */
134 INIT(false) {
135
136 },
137 /**
138 * Once the session is established, wait for open message.
139 */
140 OPENWAIT(false) {
141 @Override
142 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
143
Avantika-Huawei56c11842016-04-28 00:56:56 +0530144 log.info("Message received in OPEN WAIT State");
SureshBR25058b72015-08-13 13:05:06 +0530145
146 //check for open message
147 if (m.getType() != PcepType.OPEN) {
148 // When the message type is not open message increment the wrong packet statistics
149 h.processUnknownMsg();
150 log.debug("message is not OPEN message");
151 } else {
152
153 h.pcepPacketStats.addInPacket();
154 PcepOpenMsg pOpenmsg = (PcepOpenMsg) m;
Priyanka Bd2b28882016-04-04 16:57:04 +0530155 //Do Capability negotiation.
156 h.capabilityNegotiation(pOpenmsg);
SureshBR25058b72015-08-13 13:05:06 +0530157 log.debug("Sending handshake OPEN message");
158 h.sessionId = pOpenmsg.getPcepOpenObject().getSessionId();
159 h.pcepVersion = pOpenmsg.getPcepOpenObject().getVersion();
160
161 //setting keepalive and deadTimer
162 byte yKeepalive = pOpenmsg.getPcepOpenObject().getKeepAliveTime();
163 byte yDeadTimer = pOpenmsg.getPcepOpenObject().getDeadTime();
164 h.keepAliveTime = yKeepalive;
165 if (yKeepalive < yDeadTimer) {
166 h.deadTime = yDeadTimer;
167 } else {
168 if (DEADTIMER_MAXIMUM_VALUE > (yKeepalive * KEEPALIVE_MULTIPLE_FOR_DEADTIMER)) {
169 h.deadTime = (byte) (yKeepalive * KEEPALIVE_MULTIPLE_FOR_DEADTIMER);
170 } else {
171 h.deadTime = DEADTIMER_MAXIMUM_VALUE;
172 }
173 }
Avantika-Huawei56c11842016-04-28 00:56:56 +0530174
Avantika-Huawei7f7376a2016-05-11 17:07:50 +0530175 /*
176 * If MPLS LSR id and PCEP session socket IP addresses are not same,
177 * the MPLS LSR id will be encoded in separate TLV.
178 * We always maintain session information based on LSR ids.
179 * The socket IP is stored in channel.
180 */
Avantika-Huawei56c11842016-04-28 00:56:56 +0530181 LinkedList<PcepValueType> optionalTlvs = pOpenmsg.getPcepOpenObject().getOptionalTlv();
Avantika-Huawei3524d852016-06-04 20:44:13 +0530182 if (optionalTlvs != null) {
183 for (PcepValueType optionalTlv : optionalTlvs) {
184 if (optionalTlv instanceof NodeAttributesTlv) {
185 List<PcepValueType> subTlvs = ((NodeAttributesTlv) optionalTlv)
186 .getllNodeAttributesSubTLVs();
187 if (subTlvs == null) {
Avantika-Huawei56c11842016-04-28 00:56:56 +0530188 break;
189 }
Avantika-Huawei3524d852016-06-04 20:44:13 +0530190 for (PcepValueType subTlv : subTlvs) {
191 if (subTlv instanceof IPv4RouterIdOfLocalNodeSubTlv) {
192 h.thispccId = PccId.pccId(IpAddress
193 .valueOf(((IPv4RouterIdOfLocalNodeSubTlv) subTlv).getInt()));
194 break;
195 }
196 }
197 break;
Avantika-Huawei56c11842016-04-28 00:56:56 +0530198 }
Avantika-Huawei56c11842016-04-28 00:56:56 +0530199 }
200 }
201
202 if (h.thispccId == null) {
203 final SocketAddress address = h.channel.getRemoteAddress();
204 if (!(address instanceof InetSocketAddress)) {
205 throw new IOException("Invalid client connection. Pcc is indentifed based on IP");
206 }
207
208 final InetSocketAddress inetAddress = (InetSocketAddress) address;
209 h.thispccId = PccId.pccId(IpAddress.valueOf(inetAddress.getAddress()));
210 }
211
SureshBR25058b72015-08-13 13:05:06 +0530212 h.sendHandshakeOpenMessage();
213 h.pcepPacketStats.addOutPacket();
214 h.setState(KEEPWAIT);
SureshBR25058b72015-08-13 13:05:06 +0530215 }
216 }
217 },
218 /**
219 * Once the open messages are exchanged, wait for keep alive message.
220 */
221 KEEPWAIT(false) {
222 @Override
223 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
Avantika-Huawei56c11842016-04-28 00:56:56 +0530224 log.info("message received in KEEPWAIT state");
SureshBR25058b72015-08-13 13:05:06 +0530225 //check for keep alive message
226 if (m.getType() != PcepType.KEEP_ALIVE) {
227 // When the message type is not keep alive message increment the wrong packet statistics
228 h.processUnknownMsg();
Avantika-Huawei56c11842016-04-28 00:56:56 +0530229 log.error("message is not KEEPALIVE message");
SureshBR25058b72015-08-13 13:05:06 +0530230 } else {
231 // Set the client connected status
232 h.pcepPacketStats.addInPacket();
SureshBR25058b72015-08-13 13:05:06 +0530233 log.debug("sending keep alive message in KEEPWAIT state");
SureshBR25058b72015-08-13 13:05:06 +0530234 h.pc = h.controller.getPcepClientInstance(h.thispccId, h.sessionId, h.pcepVersion,
235 h.pcepPacketStats);
Priyanka Bd2b28882016-04-04 16:57:04 +0530236 //Get pc instance and set capabilities
237 h.pc.setCapability(h.capability);
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530238
239 // Initilialize DB sync status.
240 h.pc.setLspDbSyncStatus(NOT_SYNCED);
241 h.pc.setLabelDbSyncStatus(NOT_SYNCED);
242
SureshBR25058b72015-08-13 13:05:06 +0530243 // set the status of pcc as connected
244 h.pc.setConnected(true);
245 h.pc.setChannel(h.channel);
246
247 // set any other specific parameters to the pcc
248 h.pc.setPcVersion(h.pcepVersion);
249 h.pc.setPcSessionId(h.sessionId);
250 h.pc.setPcKeepAliveTime(h.keepAliveTime);
251 h.pc.setPcDeadTime(h.deadTime);
252 int keepAliveTimer = h.keepAliveTime & BYTE_MASK;
253 int deadTimer = h.deadTime & BYTE_MASK;
254 if (0 == h.keepAliveTime) {
255 h.deadTime = 0;
256 }
257 // handle keep alive and dead time
258 if (keepAliveTimer != PcepPipelineFactory.DEFAULT_KEEP_ALIVE_TIME
259 || deadTimer != PcepPipelineFactory.DEFAULT_DEAD_TIME) {
260
261 h.channel.getPipeline().replace("idle", "idle",
262 new IdleStateHandler(PcepPipelineFactory.TIMER, deadTimer, keepAliveTimer, 0));
263 }
264 log.debug("Dead timer : " + deadTimer);
265 log.debug("Keep alive time : " + keepAliveTimer);
266
267 //set the state handshake completion.
Avantika-Huaweifc10dca2016-06-10 16:13:55 +0530268
SureshBR25058b72015-08-13 13:05:06 +0530269 h.sendKeepAliveMessage();
270 h.pcepPacketStats.addOutPacket();
271 h.setHandshakeComplete(true);
272
273 if (!h.pc.connectClient()) {
274 disconnectDuplicate(h);
275 } else {
276 h.setState(ESTABLISHED);
Avantika-Huaweife44ea62016-05-27 19:21:24 +0530277 //Session is established, add a network configuration with LSR id and device capabilities.
Priyanka B94395bf2016-05-21 18:39:46 +0530278 h.addNode();
SureshBR25058b72015-08-13 13:05:06 +0530279 }
280 }
281 }
282 },
283 /**
284 * Once the keep alive messages are exchanged, the state is established.
285 */
286 ESTABLISHED(true) {
287 @Override
288 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
289
290 //h.channel.getPipeline().remove("waittimeout");
291 log.debug("Message received in established state " + m.getType());
292 //dispatch the message
293 h.dispatchMessage(m);
294 }
295 };
296 private boolean handshakeComplete;
297
298 ChannelState(boolean handshakeComplete) {
299 this.handshakeComplete = handshakeComplete;
300 }
301
302 void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
303 // do nothing
304 }
305
306 /**
307 * Is this a state in which the handshake has completed.
308 *
309 * @return true if the handshake is complete
310 */
311 public boolean isHandshakeComplete() {
312 return this.handshakeComplete;
313 }
314
315 protected void disconnectDuplicate(PcepChannelHandler h) {
316 log.error("Duplicated Pcc IP or incompleted cleanup - " + "disconnecting channel {}",
317 h.getClientInfoString());
318 h.duplicatePccIdFound = Boolean.TRUE;
319 h.channel.disconnect();
320 }
321
322 /**
323 * Sets handshake complete status.
324 *
325 * @param handshakeComplete status of handshake
326 */
327 public void setHandshakeComplete(boolean handshakeComplete) {
328 this.handshakeComplete = handshakeComplete;
329 }
330
331 }
332
333 @Override
334 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
335 channel = e.getChannel();
336 log.info("PCC connected from {}", channel.getRemoteAddress());
337
338 // Wait for open message from pcc client
339 setState(ChannelState.OPENWAIT);
340 }
341
342 @Override
343 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
344 log.info("Pcc disconnected callback for pc:{}. Cleaning up ...", getClientInfoString());
345 if (thispccId != null) {
346 if (!duplicatePccIdFound) {
347 // if the disconnected client (on this ChannelHandler)
348 // was not one with a duplicate-dpid, it is safe to remove all
349 // state for it at the controller. Notice that if the disconnected
350 // client was a duplicate-ip, calling the method below would clear
351 // all state for the original client (with the same ip),
352 // which we obviously don't want.
353 log.debug("{}:removal called", getClientInfoString());
354 if (pc != null) {
355 pc.removeConnectedClient();
356 }
357 } else {
358 // A duplicate was disconnected on this ChannelHandler,
359 // this is the same client reconnecting, but the original state was
360 // not cleaned up - XXX check liveness of original ChannelHandler
361 log.debug("{}:duplicate found", getClientInfoString());
362 duplicatePccIdFound = Boolean.FALSE;
363 }
364 } else {
365 log.warn("no pccip in channelHandler registered for " + "disconnected client {}", getClientInfoString());
366 }
367 }
368
369 @Override
370 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
371 PcepErrorMsg errMsg;
372 log.info("exceptionCaught: " + e.toString());
373
374 if (e.getCause() instanceof ReadTimeoutException) {
375 if (ChannelState.OPENWAIT == state) {
376 // When ReadTimeout timer is expired in OPENWAIT state, it is considered
377 // OpenWait timer.
378 errMsg = getErrorMsg(PcepErrorDetailInfo.ERROR_TYPE_1, PcepErrorDetailInfo.ERROR_VALUE_2);
379 log.debug("Sending PCEP-ERROR message to PCC.");
380 channel.write(Collections.singletonList(errMsg));
381 channel.close();
382 state = ChannelState.INIT;
383 return;
384 } else if (ChannelState.KEEPWAIT == state) {
385 // When ReadTimeout timer is expired in KEEPWAIT state, is is considered
386 // KeepWait timer.
387 errMsg = getErrorMsg(PcepErrorDetailInfo.ERROR_TYPE_1, PcepErrorDetailInfo.ERROR_VALUE_7);
388 log.debug("Sending PCEP-ERROR message to PCC.");
389 channel.write(Collections.singletonList(errMsg));
390 channel.close();
391 state = ChannelState.INIT;
392 return;
393 }
394 } else if (e.getCause() instanceof ClosedChannelException) {
395 log.debug("Channel for pc {} already closed", getClientInfoString());
396 } else if (e.getCause() instanceof IOException) {
397 log.error("Disconnecting client {} due to IO Error: {}", getClientInfoString(), e.getCause().getMessage());
398 if (log.isDebugEnabled()) {
399 // still print stack trace if debug is enabled
400 log.debug("StackTrace for previous Exception: ", e.getCause());
401 }
402 channel.close();
403 } else if (e.getCause() instanceof PcepParseException) {
404 PcepParseException errMsgParse = (PcepParseException) e.getCause();
405 byte errorType = errMsgParse.getErrorType();
406 byte errorValue = errMsgParse.getErrorValue();
407
408 if ((errorType == (byte) 0x0) && (errorValue == (byte) 0x0)) {
409 processUnknownMsg();
410 } else {
411 errMsg = getErrorMsg(errorType, errorValue);
412 log.debug("Sending PCEP-ERROR message to PCC.");
413 channel.write(Collections.singletonList(errMsg));
414 }
415 } else if (e.getCause() instanceof RejectedExecutionException) {
416 log.warn("Could not process message: queue full");
417 } else {
418 log.error("Error while processing message from client " + getClientInfoString() + "state " + this.state);
419 channel.close();
420 }
421 }
422
423 @Override
424 public String toString() {
425 return getClientInfoString();
426 }
427
428 @Override
429 public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
430 if (!isHandshakeComplete()) {
431 return;
432 }
433
434 if (e.getState() == IdleState.READER_IDLE) {
435 // When no message is received on channel for read timeout, then close
436 // the channel
437 log.info("Disconnecting client {} due to read timeout", getClientInfoString());
438 ctx.getChannel().close();
439 } else if (e.getState() == IdleState.WRITER_IDLE) {
440 // Send keep alive message
441 log.debug("Sending keep alive message due to IdleState timeout " + pc.toString());
442 pc.sendMessage(Collections.singletonList(pc.factory().buildKeepaliveMsg().build()));
443 }
444 }
445
446 @Override
447 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
448 if (e.getMessage() instanceof List) {
449 @SuppressWarnings("unchecked")
450 List<PcepMessage> msglist = (List<PcepMessage>) e.getMessage();
451 for (PcepMessage pm : msglist) {
452 // Do the actual packet processing
453 state.processPcepMessage(this, pm);
454 }
455 } else {
456 state.processPcepMessage(this, (PcepMessage) e.getMessage());
457 }
458 }
459
460 /**
461 * To set the handshake status.
462 *
463 * @param handshakeComplete value is handshake status
464 */
465 public void setHandshakeComplete(boolean handshakeComplete) {
466 this.state.setHandshakeComplete(handshakeComplete);
467 }
468
469 /**
470 * Is this a state in which the handshake has completed.
471 *
472 * @return true if the handshake is complete
473 */
474 public boolean isHandshakeComplete() {
475 return this.state.isHandshakeComplete();
476 }
477
478 /**
479 * To handle the pcep message.
480 *
481 * @param m pcep message
482 */
483 private void dispatchMessage(PcepMessage m) {
484 pc.handleMessage(m);
485 }
486
487 /**
Avantika-Huaweife44ea62016-05-27 19:21:24 +0530488 * Adds PCEP device configuration with capabilities once session is established.
Priyanka B94395bf2016-05-21 18:39:46 +0530489 */
490 private void addNode() {
491 pc.addNode(pc);
492 }
493
494 /**
Avantika-Huaweife44ea62016-05-27 19:21:24 +0530495 * Deletes PCEP device configuration when session is disconnected.
Priyanka B94395bf2016-05-21 18:39:46 +0530496 */
497 private void deleteNode() {
498 pc.deleteNode(pc.getPccId());
499 }
500
501 /**
SureshBR25058b72015-08-13 13:05:06 +0530502 * Return a string describing this client based on the already available
503 * information (ip address and/or remote socket).
504 *
505 * @return display string
506 */
507 private String getClientInfoString() {
508 if (pc != null) {
509 return pc.toString();
510 }
511 String channelString;
512 if (channel == null || channel.getRemoteAddress() == null) {
513 channelString = "?";
514 } else {
515 channelString = channel.getRemoteAddress().toString();
516 }
517 String pccIpString;
518 // TODO : implement functionality to get pcc id string
519 pccIpString = "?";
520 return String.format("[%s PCCIP[%s]]", channelString, pccIpString);
521 }
522
523 /**
524 * Update the channels state. Only called from the state machine.
525 *
526 * @param state
527 */
528 private void setState(ChannelState state) {
529 this.state = state;
530 }
531
532 /**
533 * Send handshake open message.
534 *
535 * @throws IOException,PcepParseException
536 */
537 private void sendHandshakeOpenMessage() throws IOException, PcepParseException {
538 PcepOpenObject pcepOpenobj = factory1.buildOpenObject()
539 .setSessionId(sessionId)
540 .setKeepAliveTime(keepAliveTime)
541 .setDeadTime(deadTime)
542 .build();
543 PcepMessage msg = factory1.buildOpenMsg()
544 .setPcepOpenObj(pcepOpenobj)
545 .build();
546 log.debug("Sending OPEN message to {}", channel.getRemoteAddress());
547 channel.write(Collections.singletonList(msg));
548 }
549
Priyanka Bd2b28882016-04-04 16:57:04 +0530550 //Capability negotiation
551 private void capabilityNegotiation(PcepOpenMsg pOpenmsg) {
SureshBR25058b72015-08-13 13:05:06 +0530552 LinkedList<PcepValueType> tlvList = pOpenmsg.getPcepOpenObject().getOptionalTlv();
Priyanka Bd2b28882016-04-04 16:57:04 +0530553 boolean pceccCapability = false;
554 boolean statefulPceCapability = false;
555 boolean pcInstantiationCapability = false;
Priyanka B94395bf2016-05-21 18:39:46 +0530556 boolean labelStackCapability = false;
557 boolean srCapability = false;
SureshBR25058b72015-08-13 13:05:06 +0530558
559 ListIterator<PcepValueType> listIterator = tlvList.listIterator();
560 while (listIterator.hasNext()) {
561 PcepValueType tlv = listIterator.next();
562
563 switch (tlv.getType()) {
564 case PceccCapabilityTlv.TYPE:
Priyanka Bd2b28882016-04-04 16:57:04 +0530565 pceccCapability = true;
Priyanka B94395bf2016-05-21 18:39:46 +0530566 if (((PceccCapabilityTlv) tlv).sBit()) {
567 labelStackCapability = true;
568 }
SureshBR25058b72015-08-13 13:05:06 +0530569 break;
570 case StatefulPceCapabilityTlv.TYPE:
Priyanka Bd2b28882016-04-04 16:57:04 +0530571 statefulPceCapability = true;
SureshBR25058b72015-08-13 13:05:06 +0530572 StatefulPceCapabilityTlv stetefulPcCapTlv = (StatefulPceCapabilityTlv) tlv;
573 if (stetefulPcCapTlv.getIFlag()) {
Priyanka Bd2b28882016-04-04 16:57:04 +0530574 pcInstantiationCapability = true;
SureshBR25058b72015-08-13 13:05:06 +0530575 }
576 break;
Priyanka B94395bf2016-05-21 18:39:46 +0530577 case SrPceCapabilityTlv.TYPE:
578 srCapability = true;
579 break;
SureshBR25058b72015-08-13 13:05:06 +0530580 default:
581 continue;
582 }
583 }
Priyanka B94395bf2016-05-21 18:39:46 +0530584 this.capability = new ClientCapability(pceccCapability, statefulPceCapability, pcInstantiationCapability,
585 labelStackCapability, srCapability);
SureshBR25058b72015-08-13 13:05:06 +0530586 }
587
588 /**
589 * Send keep alive message.
590 *
591 * @throws IOException when channel is disconnected
592 * @throws PcepParseException while building keep alive message
593 */
594 private void sendKeepAliveMessage() throws IOException, PcepParseException {
595 PcepMessage msg = factory1.buildKeepaliveMsg().build();
596 log.debug("Sending KEEPALIVE message to {}", channel.getRemoteAddress());
597 channel.write(Collections.singletonList(msg));
598 }
599
600 /**
601 * Send error message and close channel with pcc.
602 */
603 private void sendErrMsgAndCloseChannel() {
604 // TODO send error message
Priyanka B94395bf2016-05-21 18:39:46 +0530605 //Remove PCEP device from topology
606 deleteNode();
SureshBR25058b72015-08-13 13:05:06 +0530607 channel.close();
608 }
609
610 /**
611 * Send error message when an invalid message is received.
612 *
613 * @throws PcepParseException while building error message
614 */
615 private void sendErrMsgForInvalidMsg() throws PcepParseException {
616 byte errorType = 0x02;
617 byte errorValue = 0x00;
618 PcepErrorMsg errMsg = getErrorMsg(errorType, errorValue);
619 channel.write(Collections.singletonList(errMsg));
620 }
621
622 /**
623 * Builds pcep error message based on error value and error type.
624 *
625 * @param errorType pcep error type
626 * @param errorValue pcep error value
627 * @return pcep error message
628 * @throws PcepParseException while bulding error message
629 */
630 public PcepErrorMsg getErrorMsg(byte errorType, byte errorValue) throws PcepParseException {
Sho SHIMIZU9b8274c2015-09-04 15:54:24 -0700631 LinkedList<PcepErrorObject> llerrObj = new LinkedList<>();
SureshBR25058b72015-08-13 13:05:06 +0530632 PcepErrorMsg errMsg;
633
634 PcepErrorObject errObj = factory1.buildPcepErrorObject()
635 .setErrorValue(errorValue)
636 .setErrorType(errorType)
637 .build();
638
639 llerrObj.add(errObj);
640
SureshBR25058b72015-08-13 13:05:06 +0530641 //If Error caught in other than Openmessage
Sho SHIMIZU9b8274c2015-09-04 15:54:24 -0700642 LinkedList<PcepError> llPcepErr = new LinkedList<>();
SureshBR25058b72015-08-13 13:05:06 +0530643
644 PcepError pcepErr = factory1.buildPcepError()
645 .setErrorObjList(llerrObj)
646 .build();
647
648 llPcepErr.add(pcepErr);
649
650 PcepErrorInfo errInfo = factory1.buildPcepErrorInfo()
651 .setPcepErrorList(llPcepErr)
652 .build();
653
654 errMsg = factory1.buildPcepErrorMsg()
655 .setPcepErrorInfo(errInfo)
656 .build();
SureshBR25058b72015-08-13 13:05:06 +0530657 return errMsg;
658 }
659
660 /**
661 * Process unknown pcep message received.
662 *
663 * @throws PcepParseException while building pcep error message
664 */
665 public void processUnknownMsg() throws PcepParseException {
666 Date now = null;
667 if (pcepPacketStats.wrongPacketCount() == 0) {
668 now = new Date();
669 pcepPacketStats.setTime(now.getTime());
670 pcepPacketStats.addWrongPacket();
671 sendErrMsgForInvalidMsg();
672 }
673
674 if (pcepPacketStats.wrongPacketCount() > 1) {
675 Date lastest = new Date();
676 pcepPacketStats.addWrongPacket();
677 //converting to seconds
678 if (((lastest.getTime() - pcepPacketStats.getTime()) / 1000) > 60) {
679 now = lastest;
680 pcepPacketStats.setTime(now.getTime());
681 pcepPacketStats.resetWrongPacket();
682 pcepPacketStats.addWrongPacket();
683 } else if (((int) (lastest.getTime() - now.getTime()) / 1000) < 60) {
684 if (MAX_WRONG_COUNT_PACKET <= pcepPacketStats.wrongPacketCount()) {
685 //reset once wrong packet count reaches MAX_WRONG_COUNT_PACKET
686 pcepPacketStats.resetWrongPacket();
687 // max wrong packets received send error message and close the session
688 sendErrMsgAndCloseChannel();
689 }
690 }
691 }
692 }
693}