| /* |
| * 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.ospf.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.ospf.controller.OspfArea; |
| import org.onosproject.ospf.controller.OspfInterface; |
| import org.onosproject.ospf.controller.OspfMessage; |
| import org.onosproject.ospf.controller.OspfNbr; |
| import org.onosproject.ospf.controller.OspfProcess; |
| import org.onosproject.ospf.controller.area.OspfInterfaceImpl; |
| import org.onosproject.ospf.controller.util.OspfInterfaceType; |
| import org.onosproject.ospf.exceptions.OspfParseException; |
| import org.onosproject.ospf.protocol.util.OspfInterfaceState; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.IOException; |
| import java.nio.channels.ClosedChannelException; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.RejectedExecutionException; |
| |
| /** |
| * Channel handler deals with the OSPF channel connection. |
| * Also it dispatches messages to the appropriate handlers for processing. |
| */ |
| public class OspfInterfaceChannelHandler extends IdleStateAwareChannelHandler { |
| |
| private static final Logger log = LoggerFactory.getLogger(OspfInterfaceChannelHandler.class); |
| private static Map<Integer, Object> isisDb = null; |
| private Channel channel = null; |
| private Controller controller; |
| private List<OspfProcess> processes = null; |
| private byte[] configPacket = null; |
| private Map<Integer, OspfInterface> ospfInterfaceMap = new ConcurrentHashMap<>(); |
| |
| /** |
| * Creates an instance of OSPF channel handler. |
| * |
| * @param controller controller instance |
| * @param processes list of configured processes |
| */ |
| public OspfInterfaceChannelHandler(Controller controller, List<OspfProcess> processes) { |
| this.controller = controller; |
| this.processes = processes; |
| } |
| |
| /** |
| * Initializes the interface map with interface details. |
| * |
| * @throws Exception might throws exception |
| */ |
| public void initializeInterfaceMap() throws Exception { |
| for (OspfProcess process : processes) { |
| for (OspfArea area : process.areas()) { |
| for (OspfInterface ospfInterface : area.ospfInterfaceList()) { |
| OspfInterface anInterface = ospfInterfaceMap.get(ospfInterface.interfaceIndex()); |
| if (anInterface == null) { |
| ospfInterface.setOspfArea(area); |
| ((OspfInterfaceImpl) ospfInterface).setController(controller); |
| ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DOWN); |
| ospfInterface.setDr(Ip4Address.valueOf("0.0.0.0")); |
| ospfInterface.setBdr(Ip4Address.valueOf("0.0.0.0")); |
| ospfInterfaceMap.put(ospfInterface.interfaceIndex(), ospfInterface); |
| } |
| ((OspfInterfaceImpl) ospfInterface).setChannel(channel); |
| ospfInterface.interfaceUp(); |
| ospfInterface.startDelayedAckTimer(); |
| } |
| //Initialize the LSDB and aging process |
| area.initializeDb(); |
| } |
| } |
| } |
| |
| /** |
| * Updates the interface map with interface details. |
| * |
| * @param ospfProcesses updated process instances |
| * @throws Exception might throws exception |
| */ |
| public void updateInterfaceMap(List<OspfProcess> ospfProcesses) throws Exception { |
| for (OspfProcess ospfUpdatedProcess : ospfProcesses) { |
| for (OspfArea updatedArea : ospfUpdatedProcess.areas()) { |
| for (OspfInterface ospfUpdatedInterface : updatedArea.ospfInterfaceList()) { |
| OspfInterface ospfInterface = ospfInterfaceMap.get(ospfUpdatedInterface.interfaceIndex()); |
| if (ospfInterface == null) { |
| ospfUpdatedInterface.setOspfArea(updatedArea); |
| ((OspfInterfaceImpl) ospfUpdatedInterface).setController(controller); |
| ((OspfInterfaceImpl) ospfUpdatedInterface).setState(OspfInterfaceState.DOWN); |
| ospfUpdatedInterface.setDr(Ip4Address.valueOf("0.0.0.0")); |
| ospfUpdatedInterface.setBdr(Ip4Address.valueOf("0.0.0.0")); |
| ospfInterfaceMap.put(ospfUpdatedInterface.interfaceIndex(), ospfUpdatedInterface); |
| ((OspfInterfaceImpl) ospfUpdatedInterface).setChannel(channel); |
| ospfUpdatedInterface.interfaceUp(); |
| ospfUpdatedInterface.startDelayedAckTimer(); |
| } else { |
| ospfInterface.setOspfArea(updatedArea); |
| |
| if (ospfInterface.routerDeadIntervalTime() != ospfUpdatedInterface.routerDeadIntervalTime()) { |
| ospfInterface.setRouterDeadIntervalTime(ospfUpdatedInterface.routerDeadIntervalTime()); |
| Map<String, OspfNbr> neighbors = ospfInterface.listOfNeighbors(); |
| for (String key : neighbors.keySet()) { |
| OspfNbr ospfNbr = ospfInterface.neighbouringRouter(key); |
| ospfNbr.setRouterDeadInterval(ospfInterface.routerDeadIntervalTime()); |
| ospfNbr.stopInactivityTimeCheck(); |
| ospfNbr.startInactivityTimeCheck(); |
| } |
| } |
| if (ospfInterface.interfaceType() != ospfUpdatedInterface.interfaceType()) { |
| ospfInterface.setInterfaceType(ospfUpdatedInterface.interfaceType()); |
| if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) { |
| ospfInterface.setDr(Ip4Address.valueOf("0.0.0.0")); |
| ospfInterface.setBdr(Ip4Address.valueOf("0.0.0.0")); |
| } |
| ospfInterface.removeNeighbors(); |
| } |
| if (ospfInterface.helloIntervalTime() != ospfUpdatedInterface.helloIntervalTime()) { |
| ospfInterface.setHelloIntervalTime(ospfUpdatedInterface.helloIntervalTime()); |
| ospfInterface.stopHelloTimer(); |
| ospfInterface.startHelloTimer(); |
| } |
| ospfInterfaceMap.put(ospfInterface.interfaceIndex(), ospfInterface); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Initialize channel, start hello sender and initialize LSDB. |
| */ |
| private void initialize() throws Exception { |
| log.debug("OspfChannelHandler initialize..!!!"); |
| if (configPacket != null) { |
| log.debug("OspfChannelHandler initialize -> sentConfig packet of length ::" |
| + configPacket.length); |
| sentConfigPacket(configPacket); |
| } |
| initializeInterfaceMap(); |
| } |
| |
| @Override |
| public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent evt) throws Exception { |
| log.info("OSPF channelConnected from {}", evt.getChannel().getRemoteAddress()); |
| this.channel = evt.getChannel(); |
| initialize(); |
| } |
| |
| @Override |
| public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent evt) { |
| log.debug("OspfChannelHandler::channelDisconnected...!!!"); |
| |
| for (Integer interfaceIndex : ospfInterfaceMap.keySet()) { |
| OspfInterface anInterface = ospfInterfaceMap.get(interfaceIndex); |
| if (anInterface != null) { |
| anInterface.interfaceDown(); |
| anInterface.stopDelayedAckTimer(); |
| } |
| } |
| |
| if (controller != null) { |
| controller.connectPeer(); |
| } |
| } |
| |
| @Override |
| public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent |
| e) throws Exception { |
| log.debug("[exceptionCaught]: " + e.toString()); |
| 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 OSPF {} already closed", e.getChannel().getRemoteAddress()); |
| } else if (e.getCause() instanceof IOException) { |
| log.debug("Disconnecting OSPF {} due to IO Error: {}", e.getChannel().getRemoteAddress(), |
| e.getCause().getMessage()); |
| } else if (e.getCause() instanceof OspfParseException) { |
| OspfParseException errMsg = (OspfParseException) e.getCause(); |
| byte errorCode = errMsg.errorCode(); |
| byte errorSubCode = errMsg.errorSubCode(); |
| log.debug("Error while parsing message from OSPF {}, 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 OSPF {}, {}", |
| e.getChannel().getRemoteAddress(), e.getCause().getMessage()); |
| } |
| } |
| |
| @Override |
| public void messageReceived(ChannelHandlerContext ctx, MessageEvent |
| e) throws Exception { |
| log.debug("OspfChannelHandler::messageReceived...!!!"); |
| Object message = e.getMessage(); |
| if (message instanceof List) { |
| List<OspfMessage> ospfMessageList = (List<OspfMessage>) message; |
| log.debug("OspfChannelHandler::List of IsisMessages Size {}", ospfMessageList.size()); |
| if (ospfMessageList != null) { |
| for (OspfMessage ospfMessage : ospfMessageList) { |
| processOspfMessage(ospfMessage, ctx); |
| } |
| } else { |
| log.debug("OspfChannelHandler::OspfMessages Null List...!!"); |
| } |
| } |
| if (message instanceof OspfMessage) { |
| OspfMessage ospfMessage = (OspfMessage) message; |
| log.debug("OspfChannelHandler::OspfMessages received...!!"); |
| processOspfMessage(ospfMessage, ctx); |
| } |
| } |
| |
| /** |
| * When an OSPF message received it is handed over to this method. |
| * Based on the type of the OSPF message received it will be handed over |
| * to corresponding message handler methods. |
| * |
| * @param ospfMessage received OSPF message |
| * @param ctx channel handler context instance. |
| * @throws Exception might throws exception |
| */ |
| public void processOspfMessage(OspfMessage |
| ospfMessage, ChannelHandlerContext ctx) throws Exception { |
| log.debug("OspfChannelHandler::processOspfMessage...!!!"); |
| int interfaceIndex = ospfMessage.interfaceIndex(); |
| OspfInterface ospfInterface = ospfInterfaceMap.get(interfaceIndex); |
| if (ospfInterface != null) { |
| ospfInterface.processOspfMessage(ospfMessage, ctx); |
| } |
| } |
| |
| /** |
| * Sends the interface configuration packet to server. |
| * |
| * @param configPacket interface configuration |
| */ |
| public void sentConfigPacket(byte[] configPacket) { |
| if (channel != null) { |
| channel.write(configPacket); |
| log.debug("OspfChannelHandler sentConfigPacket packet sent..!!!"); |
| } else { |
| log.debug("OspfChannelHandler sentConfigPacket channel not connected - re try..!!!"); |
| this.configPacket = configPacket; |
| } |
| } |
| } |