blob: 9d499828bfae3cfd18b38e06befa0209de0898c7 [file] [log] [blame]
Hyunsun Moon90163ba2016-10-12 13:35:14 -07001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
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.ofagent.impl;
17
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090018import io.netty.channel.Channel;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070019import io.netty.channel.ChannelDuplexHandler;
20import io.netty.channel.ChannelHandlerContext;
Daniel Parkbe6b6732016-11-11 15:52:19 +090021import io.netty.handler.timeout.ReadTimeoutException;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070022import org.onosproject.ofagent.api.OFSwitch;
Daniel Parkbe6b6732016-11-11 15:52:19 +090023import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070024import org.projectfloodlight.openflow.protocol.OFMessage;
25import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
27
Daniel Parkbe6b6732016-11-11 15:52:19 +090028import java.io.IOException;
29import java.nio.channels.ClosedChannelException;
Daniel Parkbe6b6732016-11-11 15:52:19 +090030import java.util.concurrent.RejectedExecutionException;
31
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090032import static org.onosproject.ofagent.impl.OFChannelHandler.ChannelState.INIT;
33
Hyunsun Moon90163ba2016-10-12 13:35:14 -070034/**
35 * Implementation of OpenFlow channel handler.
36 * It processes OpenFlow message according to the channel state.
37 */
38public final class OFChannelHandler extends ChannelDuplexHandler {
39
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090040 private static final String MSG_CHANNEL_STATE = "Set channel(%s) state: %s";
41
Hyunsun Moon90163ba2016-10-12 13:35:14 -070042 private final Logger log = LoggerFactory.getLogger(getClass());
43 private final OFSwitch ofSwitch;
44
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090045 private Channel channel;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070046 private ChannelState state;
47
Daniel Parkbe6b6732016-11-11 15:52:19 +090048 enum ChannelState {
Hyunsun Moon90163ba2016-10-12 13:35:14 -070049
50 INIT {
51 @Override
52 void processOFMessage(final OFChannelHandler handler,
53 final OFMessage msg) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -040054 logProcessOFMessageDetails(handler, msg, this);
Hyunsun Moon90163ba2016-10-12 13:35:14 -070055 // TODO implement
56 }
57 },
58 WAIT_HELLO {
59 @Override
60 void processOFMessage(final OFChannelHandler handler,
61 final OFMessage msg) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -040062 logProcessOFMessageDetails(handler, msg, this);
Daniel Parkbe6b6732016-11-11 15:52:19 +090063 switch (msg.getType()) {
64 case HELLO:
65 handler.setState(ChannelState.WAIT_FEATURE_REQUEST);
66 break;
67 default:
68 handler.illegalMessageReceived(msg);
69 break;
70 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -070071 }
72 },
73 WAIT_FEATURE_REQUEST {
74 @Override
75 void processOFMessage(final OFChannelHandler handler,
76 final OFMessage msg) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -040077 logProcessOFMessageDetails(handler, msg, this);
Daniel Parkbe6b6732016-11-11 15:52:19 +090078 switch (msg.getType()) {
79 case FEATURES_REQUEST:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090080 handler.ofSwitch.processFeaturesRequest(handler.channel, msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +090081 handler.setState(ChannelState.ESTABLISHED);
82 break;
83 case ECHO_REQUEST:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090084 handler.ofSwitch.processEchoRequest(handler.channel, msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +090085 break;
86 case ERROR:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090087 handler.logErrorClose((OFErrorMsg) msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +090088 break;
89 default:
90 handler.illegalMessageReceived(msg);
91 break;
92
93 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -070094 }
95 },
96 ESTABLISHED {
97 @Override
98 void processOFMessage(final OFChannelHandler handler,
99 final OFMessage msg) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400100 logProcessOFMessageDetails(handler, msg, this);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700101 // TODO implement
102 // TODO add this channel to ofSwitch role service
Daniel Parkbe6b6732016-11-11 15:52:19 +0900103 switch (msg.getType()) {
104 case STATS_REQUEST:
105 //TODO implement
106 //TODO: use vNetService to build OFPortDesc.
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400107 handler.ofSwitch.processStatsRequest(handler.channel, msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900108 break;
109 case SET_CONFIG:
110 //TODO implement
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400111 handler.ofSwitch.processSetConfigMessage(handler.channel, msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900112 break;
113 case GET_CONFIG_REQUEST:
114 //TODO implement
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400115 handler.ofSwitch.processGetConfigRequest(handler.channel, msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900116 break;
117 case BARRIER_REQUEST:
118 //TODO implement
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400119 handler.ofSwitch.processBarrierRequest(handler.channel, msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900120 break;
121 case ECHO_REQUEST:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900122 handler.ofSwitch.processEchoRequest(handler.channel, msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900123 break;
124 case ERROR:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900125 handler.logErrorClose((OFErrorMsg) msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900126 break;
127 default:
128 handler.unhandledMessageReceived(msg);
129 break;
130 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700131 }
132 };
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900133
134 abstract void processOFMessage(final OFChannelHandler handler, final OFMessage msg);
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400135
136 private static void logProcessOFMessageDetails(final OFChannelHandler handler,
137 final OFMessage msg, ChannelState chnState) {
138 handler.log.trace("Channel state: {} dpid: {} processOFMessage type: {} nsg: {}",
139 chnState, handler.ofSwitch.dpid(), msg.getType(), msg);
140 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700141 }
142
143 /**
144 * Default constructor.
145 *
146 * @param ofSwitch openflow switch that owns this channel
147 */
148 public OFChannelHandler(OFSwitch ofSwitch) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900149 super();
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700150 this.ofSwitch = ofSwitch;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900151 setState(INIT);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700152 }
153
154 @Override
155 public void channelActive(ChannelHandlerContext ctx) throws Exception {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900156 this.channel = ctx.channel();
157 // FIXME move this to channel handler and add channel when OF handshake is done
158 ofSwitch.addControllerChannel(channel);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900159 try {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900160 ofSwitch.sendOfHello(channel);
161 log.trace("Send OF_13 Hello to {}", channel.remoteAddress());
Daniel Parkbe6b6732016-11-11 15:52:19 +0900162 setState(ChannelState.WAIT_HELLO);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900163 } catch (Exception ex) {
164 log.error("Failed sending OF_13 Hello to {} for {}", channel.remoteAddress(), ex.getMessage());
Daniel Parkbe6b6732016-11-11 15:52:19 +0900165 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700166 }
167
168 @Override
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900169 public void channelInactive(ChannelHandlerContext ctx) {
170 ofSwitch.deleteControllerChannel(channel);
171 log.info("Device {} disconnected from controller {}", ofSwitch.dpid(), channel.remoteAddress());
172 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700173
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900174 @Override
175 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900176 try {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900177 state.processOFMessage(this, (OFMessage) msg);
178 } catch (Exception ex) {
179 ctx.fireExceptionCaught(ex);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700180 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700181 }
182
183 @Override
184 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900185 if (cause instanceof ReadTimeoutException) {
186 log.error("Connection closed because of ReadTimeoutException {}", cause.getMessage());
187 } else if (cause instanceof ClosedChannelException) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900188 log.error("ClosedChannelException occurred");
Daniel Parkbe6b6732016-11-11 15:52:19 +0900189 return;
190 } else if (cause instanceof RejectedExecutionException) {
191 log.error("Could not process message: queue full");
192 } else if (cause instanceof IOException) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900193 log.error("IOException occurred");
Daniel Parkbe6b6732016-11-11 15:52:19 +0900194 } else {
195 log.error("Error while processing message from switch {}", cause.getMessage());
196 }
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900197 channel.close();
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700198 }
199
200 private void setState(ChannelState state) {
201 this.state = state;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900202 if (state != INIT) {
203 log.debug(String.format(MSG_CHANNEL_STATE, channel.remoteAddress(), state.name()));
204 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700205 }
Daniel Parkbe6b6732016-11-11 15:52:19 +0900206
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900207 private void logErrorClose(OFErrorMsg errorMsg) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900208 log.error("{} from switch {} in state {}",
209 errorMsg,
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900210 ofSwitch.dpid(),
Daniel Parkbe6b6732016-11-11 15:52:19 +0900211 state);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900212 channel.close();
Daniel Parkbe6b6732016-11-11 15:52:19 +0900213 }
214
215 private void illegalMessageReceived(OFMessage ofMessage) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400216 log.warn("Controller should never send message {} to switch {} in current state {}",
217 ofMessage.getType(), ofSwitch.dpid(), state);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900218 }
219
220 private void unhandledMessageReceived(OFMessage ofMessage) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400221 log.warn("Unexpected message {} received for switch {} in state {}",
222 ofMessage.getType(), ofSwitch.dpid(), state);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900223 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700224}