blob: 937935b4b758f0fa31d41421e31388180fe48797 [file] [log] [blame]
tejeshwer degala3fe1ed52016-04-22 17:04:01 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
tejeshwer degala3fe1ed52016-04-22 17:04:01 +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 */
16package org.onosproject.isis.controller.impl;
17
18import org.jboss.netty.channel.Channel;
19import org.jboss.netty.channel.ChannelHandlerContext;
20import org.jboss.netty.channel.ChannelStateEvent;
21import org.jboss.netty.channel.ExceptionEvent;
22import org.jboss.netty.channel.MessageEvent;
23import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
24import org.jboss.netty.handler.timeout.ReadTimeoutException;
25import org.onlab.packet.Ip4Address;
26import org.onosproject.isis.controller.IsisInterface;
27import org.onosproject.isis.controller.IsisLsdb;
28import org.onosproject.isis.controller.IsisMessage;
29import org.onosproject.isis.controller.IsisProcess;
30import org.onosproject.isis.controller.impl.lsdb.DefaultIsisLsdb;
31import org.onosproject.isis.exceptions.IsisParseException;
32import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
35import java.io.IOException;
36import java.nio.channels.ClosedChannelException;
37import java.util.ArrayList;
38import java.util.List;
39import java.util.Map;
40import java.util.Set;
41import java.util.concurrent.ConcurrentHashMap;
42import java.util.concurrent.RejectedExecutionException;
43import java.util.concurrent.ScheduledExecutorService;
44
45/**
46 * Channel handler deals with the ISIS channel connection.
47 * Also it dispatches messages to the appropriate handlers for processing.
48 */
49public class IsisChannelHandler extends IdleStateAwareChannelHandler {
50
51 private static final Logger log = LoggerFactory.getLogger(IsisChannelHandler.class);
52 private static Map<Integer, Object> isisDb = null;
sunish vkc3824e82016-05-11 19:38:24 +053053 private Channel channel = null;
tejeshwer degala3fe1ed52016-04-22 17:04:01 +053054 private Controller controller;
55 private List<IsisProcess> processes = null;
56 private List<ScheduledExecutorService> executorList = new ArrayList<>();
57 private byte[] configPacket = null;
58 private Map<Integer, IsisInterface> isisInterfaceMap = new ConcurrentHashMap<>();
59 private IsisLsdb isisLsdb = new DefaultIsisLsdb();
60 private List<Ip4Address> interfaceIps = new ArrayList<>();
61
62 /**
63 * Creates an instance of ISIS channel handler.
64 *
65 * @param controller controller instance
66 * @param processes list of configured processes
67 */
68 public IsisChannelHandler(Controller controller, List<IsisProcess> processes) {
69 this.controller = controller;
70 this.processes = processes;
sunish vk7bdf4d42016-06-24 12:29:43 +053071 ((DefaultIsisLsdb) isisLsdb).setController(this.controller);
72 ((DefaultIsisLsdb) isisLsdb).setIsisInterface(isisInterfaceList());
73 }
74
75 private List<IsisInterface> isisInterfaceList() {
76 List<IsisInterface> isisInterfaceList = new ArrayList<>();
77 for (Integer key : isisInterfaceMap.keySet()) {
78 isisInterfaceList.add(isisInterfaceMap.get(key));
79 }
80 return isisInterfaceList;
tejeshwer degala3fe1ed52016-04-22 17:04:01 +053081 }
82
83 /**
84 * Initializes the interface map with interface details.
85 */
86 public void initializeInterfaceMap() {
87 for (IsisProcess process : processes) {
88 for (IsisInterface isisInterface : process.isisInterfaceList()) {
sunish vkc3824e82016-05-11 19:38:24 +053089 IsisInterface anInterface = isisInterfaceMap.get(isisInterface.interfaceIndex());
90 if (anInterface == null) {
91 isisInterfaceMap.put(isisInterface.interfaceIndex(), isisInterface);
92 interfaceIps.add(isisInterface.interfaceIpAddress());
93 }
tejeshwer degala3fe1ed52016-04-22 17:04:01 +053094 }
95 }
96 //Initializes the interface with all interface ip details - for ls pdu generation
97 initializeInterfaceIpList();
98 }
99
100 /**
101 * Updates the interface map with interface details.
102 *
103 * @param isisProcesses updated process instances
104 */
105 public void updateInterfaceMap(List<IsisProcess> isisProcesses) {
106 for (IsisProcess isisUpdatedProcess : isisProcesses) {
107 for (IsisInterface isisUpdatedInterface : isisUpdatedProcess.isisInterfaceList()) {
108 IsisInterface isisInterface = isisInterfaceMap.get(isisUpdatedInterface.interfaceIndex());
109 if (isisInterface == null) {
sunish vk4b5ce002016-05-09 20:18:35 +0530110 isisInterfaceMap.put(isisUpdatedInterface.interfaceIndex(), isisUpdatedInterface);
111 interfaceIps.add(isisUpdatedInterface.interfaceIpAddress());
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530112 } else {
rpatodiya23a94b12017-01-20 14:01:14 +0530113 if (!isisInterface.intermediateSystemName().equals(isisUpdatedInterface.intermediateSystemName())) {
sunish vk4b5ce002016-05-09 20:18:35 +0530114 isisInterface.setIntermediateSystemName(isisUpdatedInterface.intermediateSystemName());
115 }
116 if (isisInterface.reservedPacketCircuitType() != isisUpdatedInterface.reservedPacketCircuitType()) {
117 isisInterface.setReservedPacketCircuitType(isisUpdatedInterface.reservedPacketCircuitType());
118 isisInterface.removeNeighbors();
119 }
rpatodiya23a94b12017-01-20 14:01:14 +0530120 if (!isisInterface.circuitId().equals(isisUpdatedInterface.circuitId())) {
sunish vk4b5ce002016-05-09 20:18:35 +0530121 isisInterface.setCircuitId(isisUpdatedInterface.circuitId());
122 }
123 if (isisInterface.networkType() != isisUpdatedInterface.networkType()) {
124 isisInterface.setNetworkType(isisUpdatedInterface.networkType());
125 isisInterface.removeNeighbors();
126 }
rpatodiya23a94b12017-01-20 14:01:14 +0530127 if (!isisInterface.areaAddress().equals(isisUpdatedInterface.areaAddress())) {
sunish vk4b5ce002016-05-09 20:18:35 +0530128 isisInterface.setAreaAddress(isisUpdatedInterface.areaAddress());
129 }
130 if (isisInterface.holdingTime() != isisUpdatedInterface.holdingTime()) {
131 isisInterface.setHoldingTime(isisUpdatedInterface.holdingTime());
132 }
133 if (isisInterface.helloInterval() != isisUpdatedInterface.helloInterval()) {
134 isisInterface.setHelloInterval(isisUpdatedInterface.helloInterval());
135 isisInterface.stopHelloSender();
136 isisInterface.startHelloSender(channel);
137 }
138
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530139 isisInterfaceMap.put(isisInterface.interfaceIndex(), isisInterface);
140 }
141 }
142 }
143 }
144
145 /**
146 * Initializes the interface with all interface ip details.
147 */
148 public void initializeInterfaceIpList() {
149 for (IsisProcess process : processes) {
150 for (IsisInterface isisInterface : process.isisInterfaceList()) {
151 ((DefaultIsisInterface) isisInterface).setAllConfiguredInterfaceIps(interfaceIps);
152 }
153 }
154 }
155
156 /**
157 * Initialize channel, start hello sender and initialize LSDB.
158 */
159 private void initialize() {
160 log.debug("IsisChannelHandler initialize..!!!");
161 if (configPacket != null) {
162 log.debug("IsisChannelHandler initialize -> sentConfig packet of length ::"
163 + configPacket.length);
164 sentConfigPacket(configPacket);
165 }
sunish vkc3824e82016-05-11 19:38:24 +0530166 initializeInterfaceMap();
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530167 //start the hello timer
168 startHelloSender();
169 //Initialize Database
170 isisLsdb.initializeDb();
171 }
172
173 @Override
174 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent evt) throws Exception {
175 log.info("ISIS channelConnected from {}", evt.getChannel().getRemoteAddress());
176 this.channel = evt.getChannel();
177 initialize();
178 }
179
180 @Override
181 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent evt) {
182 log.debug("IsisChannelHandler::channelDisconnected...!!!");
sunish vk4b5ce002016-05-09 20:18:35 +0530183 if (controller != null) {
184 controller.connectPeer();
sunish vkc3824e82016-05-11 19:38:24 +0530185 stopHelloSender();
sunish vk4b5ce002016-05-09 20:18:35 +0530186 }
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530187 }
188
189 @Override
190 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530191 if (e.getCause() instanceof ReadTimeoutException) {
sunish vk7bdf4d42016-06-24 12:29:43 +0530192 log.debug("Disconnecting device {} due to read timeout", e.getChannel().getRemoteAddress());
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530193 return;
194 } else if (e.getCause() instanceof ClosedChannelException) {
195 log.debug("Channel for ISIS {} already closed", e.getChannel().getRemoteAddress());
196 } else if (e.getCause() instanceof IOException) {
sunish vk7bdf4d42016-06-24 12:29:43 +0530197 log.debug("Disconnecting ISIS {} due to IO Error: {}", e.getChannel().getRemoteAddress(),
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530198 e.getCause().getMessage());
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530199 } else if (e.getCause() instanceof IsisParseException) {
200 IsisParseException errMsg = (IsisParseException) e.getCause();
201 byte errorCode = errMsg.errorCode();
202 byte errorSubCode = errMsg.errorSubCode();
sunish vk7bdf4d42016-06-24 12:29:43 +0530203 log.debug("Error while parsing message from ISIS {}, ErrorCode {}",
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530204 e.getChannel().getRemoteAddress(), errorCode);
205 } else if (e.getCause() instanceof RejectedExecutionException) {
sunish vk7bdf4d42016-06-24 12:29:43 +0530206 log.debug("Could not process message: queue full");
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530207 } else {
sunish vk7bdf4d42016-06-24 12:29:43 +0530208 log.debug("Error while processing message from ISIS {}, {}",
sunish vk4b5ce002016-05-09 20:18:35 +0530209 e.getChannel().getRemoteAddress(), e.getCause().getMessage());
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530210 }
211 }
212
213 @Override
214 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
215 log.debug("IsisChannelHandler::messageReceived...!!!");
216 Object message = e.getMessage();
217 if (message instanceof List) {
218 List<IsisMessage> isisMessageList = (List<IsisMessage>) message;
219 log.debug("IsisChannelHandler::List of IsisMessages Size {}", isisMessageList.size());
Ray Milkeyfe0e0852018-01-18 11:14:05 -0800220
221 for (IsisMessage isisMessage : isisMessageList) {
222 processIsisMessage(isisMessage, ctx);
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530223 }
224 }
225 if (message instanceof IsisMessage) {
226 IsisMessage isisMessage = (IsisMessage) message;
227 log.debug("IsisChannelHandler::IsisMessages received...!!");
228 processIsisMessage(isisMessage, ctx);
229 }
230 }
231
232 /**
233 * When an ISIS message received it is handed over to this method.
234 * Based on the type of the ISIS message received it will be handed over
235 * to corresponding message handler methods.
236 *
237 * @param isisMessage received ISIS message
238 * @param ctx channel handler context instance.
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530239 */
Ray Milkey2b4958a2018-02-06 18:59:06 -0800240 public void processIsisMessage(IsisMessage isisMessage, ChannelHandlerContext ctx) {
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530241 log.debug("IsisChannelHandler::processIsisMessage...!!!");
242 int interfaceIndex = isisMessage.interfaceIndex();
243 IsisInterface isisInterface = isisInterfaceMap.get(interfaceIndex);
244 isisInterface.processIsisMessage(isisMessage, isisLsdb, channel);
245 }
246
247 /**
248 * Starts the hello timer which sends hello packet every configured seconds.
249 */
250 public void startHelloSender() {
251 log.debug("IsisController::startHelloSender");
252 Set<Integer> interfaceIndexes = isisInterfaceMap.keySet();
253 for (Integer interfaceIndex : interfaceIndexes) {
254 IsisInterface isisInterface = isisInterfaceMap.get(interfaceIndex);
255 isisInterface.startHelloSender(channel);
256 }
257 }
258
259 /**
260 * Stops the hello timer.
261 */
262 public void stopHelloSender() {
263 log.debug("ISISChannelHandler::stopHelloTimer ");
sunish vkc3824e82016-05-11 19:38:24 +0530264 log.debug("IsisController::startHelloSender");
265 Set<Integer> interfaceIndexes = isisInterfaceMap.keySet();
266 for (Integer interfaceIndex : interfaceIndexes) {
267 IsisInterface isisInterface = isisInterfaceMap.get(interfaceIndex);
268 isisInterface.stopHelloSender();
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530269 }
270 }
271
272 /**
273 * Sends the interface configuration packet to server.
274 *
275 * @param configPacket interface configuration
276 */
277 public void sentConfigPacket(byte[] configPacket) {
sunish vk7bdf4d42016-06-24 12:29:43 +0530278 if (channel != null && channel.isConnected() && channel.isOpen()) {
tejeshwer degala3fe1ed52016-04-22 17:04:01 +0530279 channel.write(configPacket);
280 log.debug("IsisChannelHandler sentConfigPacket packet sent..!!!");
281 } else {
282 log.debug("IsisChannelHandler sentConfigPacket channel not connected - re try..!!!");
283 this.configPacket = configPacket;
284 }
285 }
286}