blob: 38e98d1e250981f6d4b9895643795a95448ee169 [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.isis.controller.impl;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.ReadTimeoutException;
import org.onlab.packet.Ip4Address;
import org.onosproject.isis.controller.IsisInterface;
import org.onosproject.isis.controller.IsisLsdb;
import org.onosproject.isis.controller.IsisMessage;
import org.onosproject.isis.controller.IsisProcess;
import org.onosproject.isis.controller.impl.lsdb.DefaultIsisLsdb;
import org.onosproject.isis.exceptions.IsisParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
/**
* Channel handler deals with the ISIS channel connection.
* Also it dispatches messages to the appropriate handlers for processing.
*/
public class IsisChannelHandler extends IdleStateAwareChannelHandler {
private static final Logger log = LoggerFactory.getLogger(IsisChannelHandler.class);
private static Map<Integer, Object> isisDb = null;
private Channel channel = null;
private Controller controller;
private List<IsisProcess> processes = null;
private List<ScheduledExecutorService> executorList = new ArrayList<>();
private byte[] configPacket = null;
private Map<Integer, IsisInterface> isisInterfaceMap = new ConcurrentHashMap<>();
private IsisLsdb isisLsdb = new DefaultIsisLsdb();
private List<Ip4Address> interfaceIps = new ArrayList<>();
/**
* Creates an instance of ISIS channel handler.
*
* @param controller controller instance
* @param processes list of configured processes
*/
public IsisChannelHandler(Controller controller, List<IsisProcess> processes) {
this.controller = controller;
this.processes = processes;
((DefaultIsisLsdb) isisLsdb).setController(this.controller);
((DefaultIsisLsdb) isisLsdb).setIsisInterface(isisInterfaceList());
}
private List<IsisInterface> isisInterfaceList() {
List<IsisInterface> isisInterfaceList = new ArrayList<>();
for (Integer key : isisInterfaceMap.keySet()) {
isisInterfaceList.add(isisInterfaceMap.get(key));
}
return isisInterfaceList;
}
/**
* Initializes the interface map with interface details.
*/
public void initializeInterfaceMap() {
for (IsisProcess process : processes) {
for (IsisInterface isisInterface : process.isisInterfaceList()) {
IsisInterface anInterface = isisInterfaceMap.get(isisInterface.interfaceIndex());
if (anInterface == null) {
isisInterfaceMap.put(isisInterface.interfaceIndex(), isisInterface);
interfaceIps.add(isisInterface.interfaceIpAddress());
}
}
}
//Initializes the interface with all interface ip details - for ls pdu generation
initializeInterfaceIpList();
}
/**
* Updates the interface map with interface details.
*
* @param isisProcesses updated process instances
*/
public void updateInterfaceMap(List<IsisProcess> isisProcesses) {
for (IsisProcess isisUpdatedProcess : isisProcesses) {
for (IsisInterface isisUpdatedInterface : isisUpdatedProcess.isisInterfaceList()) {
IsisInterface isisInterface = isisInterfaceMap.get(isisUpdatedInterface.interfaceIndex());
if (isisInterface == null) {
isisInterfaceMap.put(isisUpdatedInterface.interfaceIndex(), isisUpdatedInterface);
interfaceIps.add(isisUpdatedInterface.interfaceIpAddress());
} else {
if (isisInterface.intermediateSystemName() != isisUpdatedInterface.intermediateSystemName()) {
isisInterface.setIntermediateSystemName(isisUpdatedInterface.intermediateSystemName());
}
if (isisInterface.reservedPacketCircuitType() != isisUpdatedInterface.reservedPacketCircuitType()) {
isisInterface.setReservedPacketCircuitType(isisUpdatedInterface.reservedPacketCircuitType());
isisInterface.removeNeighbors();
}
if (isisInterface.circuitId() != isisUpdatedInterface.circuitId()) {
isisInterface.setCircuitId(isisUpdatedInterface.circuitId());
}
if (isisInterface.networkType() != isisUpdatedInterface.networkType()) {
isisInterface.setNetworkType(isisUpdatedInterface.networkType());
isisInterface.removeNeighbors();
}
if (isisInterface.areaAddress() != isisUpdatedInterface.areaAddress()) {
isisInterface.setAreaAddress(isisUpdatedInterface.areaAddress());
}
if (isisInterface.holdingTime() != isisUpdatedInterface.holdingTime()) {
isisInterface.setHoldingTime(isisUpdatedInterface.holdingTime());
}
if (isisInterface.helloInterval() != isisUpdatedInterface.helloInterval()) {
isisInterface.setHelloInterval(isisUpdatedInterface.helloInterval());
isisInterface.stopHelloSender();
isisInterface.startHelloSender(channel);
}
isisInterfaceMap.put(isisInterface.interfaceIndex(), isisInterface);
}
}
}
}
/**
* Initializes the interface with all interface ip details.
*/
public void initializeInterfaceIpList() {
for (IsisProcess process : processes) {
for (IsisInterface isisInterface : process.isisInterfaceList()) {
((DefaultIsisInterface) isisInterface).setAllConfiguredInterfaceIps(interfaceIps);
}
}
}
/**
* Initialize channel, start hello sender and initialize LSDB.
*/
private void initialize() {
log.debug("IsisChannelHandler initialize..!!!");
if (configPacket != null) {
log.debug("IsisChannelHandler initialize -> sentConfig packet of length ::"
+ configPacket.length);
sentConfigPacket(configPacket);
}
initializeInterfaceMap();
//start the hello timer
startHelloSender();
//Initialize Database
isisLsdb.initializeDb();
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent evt) throws Exception {
log.info("ISIS channelConnected from {}", evt.getChannel().getRemoteAddress());
this.channel = evt.getChannel();
initialize();
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent evt) {
log.debug("IsisChannelHandler::channelDisconnected...!!!");
if (controller != null) {
controller.connectPeer();
stopHelloSender();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
if (e.getCause() instanceof ReadTimeoutException) {
log.debug("Disconnecting device {} due to read timeout", e.getChannel().getRemoteAddress());
return;
} else if (e.getCause() instanceof ClosedChannelException) {
log.debug("Channel for ISIS {} already closed", e.getChannel().getRemoteAddress());
} else if (e.getCause() instanceof IOException) {
log.debug("Disconnecting ISIS {} due to IO Error: {}", e.getChannel().getRemoteAddress(),
e.getCause().getMessage());
} else if (e.getCause() instanceof IsisParseException) {
IsisParseException errMsg = (IsisParseException) e.getCause();
byte errorCode = errMsg.errorCode();
byte errorSubCode = errMsg.errorSubCode();
log.debug("Error while parsing message from ISIS {}, ErrorCode {}",
e.getChannel().getRemoteAddress(), errorCode);
} else if (e.getCause() instanceof RejectedExecutionException) {
log.debug("Could not process message: queue full");
} else {
log.debug("Error while processing message from ISIS {}, {}",
e.getChannel().getRemoteAddress(), e.getCause().getMessage());
}
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
log.debug("IsisChannelHandler::messageReceived...!!!");
Object message = e.getMessage();
if (message instanceof List) {
List<IsisMessage> isisMessageList = (List<IsisMessage>) message;
log.debug("IsisChannelHandler::List of IsisMessages Size {}", isisMessageList.size());
if (isisMessageList != null) {
for (IsisMessage isisMessage : isisMessageList) {
processIsisMessage(isisMessage, ctx);
}
} else {
log.debug("IsisChannelHandler::IsisMessages Null List...!!");
}
}
if (message instanceof IsisMessage) {
IsisMessage isisMessage = (IsisMessage) message;
log.debug("IsisChannelHandler::IsisMessages received...!!");
processIsisMessage(isisMessage, ctx);
}
}
/**
* When an ISIS message received it is handed over to this method.
* Based on the type of the ISIS message received it will be handed over
* to corresponding message handler methods.
*
* @param isisMessage received ISIS message
* @param ctx channel handler context instance.
* @throws Exception might throws exception
*/
public void processIsisMessage(IsisMessage isisMessage, ChannelHandlerContext ctx) throws Exception {
log.debug("IsisChannelHandler::processIsisMessage...!!!");
int interfaceIndex = isisMessage.interfaceIndex();
IsisInterface isisInterface = isisInterfaceMap.get(interfaceIndex);
isisInterface.processIsisMessage(isisMessage, isisLsdb, channel);
}
/**
* Starts the hello timer which sends hello packet every configured seconds.
*/
public void startHelloSender() {
log.debug("IsisController::startHelloSender");
Set<Integer> interfaceIndexes = isisInterfaceMap.keySet();
for (Integer interfaceIndex : interfaceIndexes) {
IsisInterface isisInterface = isisInterfaceMap.get(interfaceIndex);
isisInterface.startHelloSender(channel);
}
}
/**
* Stops the hello timer.
*/
public void stopHelloSender() {
log.debug("ISISChannelHandler::stopHelloTimer ");
log.debug("IsisController::startHelloSender");
Set<Integer> interfaceIndexes = isisInterfaceMap.keySet();
for (Integer interfaceIndex : interfaceIndexes) {
IsisInterface isisInterface = isisInterfaceMap.get(interfaceIndex);
isisInterface.stopHelloSender();
}
}
/**
* Sends the interface configuration packet to server.
*
* @param configPacket interface configuration
*/
public void sentConfigPacket(byte[] configPacket) {
if (channel != null && channel.isConnected() && channel.isOpen()) {
channel.write(configPacket);
log.debug("IsisChannelHandler sentConfigPacket packet sent..!!!");
} else {
log.debug("IsisChannelHandler sentConfigPacket channel not connected - re try..!!!");
this.configPacket = configPacket;
}
}
}