blob: ddfadc2636de2f8ec31251bef29c943139ceea29 [file] [log] [blame]
Hyunsun Moon90163ba2016-10-12 13:35:14 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon90163ba2016-10-12 13:35:14 -07003 *
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;
Claudine Chiu7c6d51c2017-06-15 23:13:51 -0400124 case ROLE_REQUEST:
125 handler.ofSwitch.processRoleRequest(handler.channel, msg);
126 break;
Claudine Chiu5c184e12017-08-08 21:21:38 -0400127 case PACKET_OUT:
128 // TODO: check if this is lldp - ignore if it is not lldp
129 handler.ofSwitch.processLldp(handler.channel, msg);
130 break;
Claudine Chiu20cbd452017-08-30 19:23:11 -0400131 case FLOW_MOD:
132 case PORT_MOD:
133 case GROUP_MOD:
134 case METER_MOD:
135 case TABLE_MOD:
136 handler.ofSwitch.processControllerCommand(handler.channel, msg);
137 break;
Daniel Parkbe6b6732016-11-11 15:52:19 +0900138 case ERROR:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900139 handler.logErrorClose((OFErrorMsg) msg);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900140 break;
141 default:
142 handler.unhandledMessageReceived(msg);
143 break;
144 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700145 }
146 };
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900147
148 abstract void processOFMessage(final OFChannelHandler handler, final OFMessage msg);
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400149
150 private static void logProcessOFMessageDetails(final OFChannelHandler handler,
151 final OFMessage msg, ChannelState chnState) {
152 handler.log.trace("Channel state: {} dpid: {} processOFMessage type: {} nsg: {}",
153 chnState, handler.ofSwitch.dpid(), msg.getType(), msg);
154 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700155 }
156
157 /**
158 * Default constructor.
159 *
160 * @param ofSwitch openflow switch that owns this channel
161 */
162 public OFChannelHandler(OFSwitch ofSwitch) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900163 super();
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700164 this.ofSwitch = ofSwitch;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900165 setState(INIT);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700166 }
167
168 @Override
169 public void channelActive(ChannelHandlerContext ctx) throws Exception {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900170 this.channel = ctx.channel();
171 // FIXME move this to channel handler and add channel when OF handshake is done
172 ofSwitch.addControllerChannel(channel);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900173 try {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900174 ofSwitch.sendOfHello(channel);
175 log.trace("Send OF_13 Hello to {}", channel.remoteAddress());
Daniel Parkbe6b6732016-11-11 15:52:19 +0900176 setState(ChannelState.WAIT_HELLO);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900177 } catch (Exception ex) {
178 log.error("Failed sending OF_13 Hello to {} for {}", channel.remoteAddress(), ex.getMessage());
Daniel Parkbe6b6732016-11-11 15:52:19 +0900179 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700180 }
181
182 @Override
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900183 public void channelInactive(ChannelHandlerContext ctx) {
184 ofSwitch.deleteControllerChannel(channel);
185 log.info("Device {} disconnected from controller {}", ofSwitch.dpid(), channel.remoteAddress());
186 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700187
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900188 @Override
189 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900190 try {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900191 state.processOFMessage(this, (OFMessage) msg);
192 } catch (Exception ex) {
193 ctx.fireExceptionCaught(ex);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700194 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700195 }
196
197 @Override
198 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900199 if (cause instanceof ReadTimeoutException) {
200 log.error("Connection closed because of ReadTimeoutException {}", cause.getMessage());
201 } else if (cause instanceof ClosedChannelException) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900202 log.error("ClosedChannelException occurred");
Daniel Parkbe6b6732016-11-11 15:52:19 +0900203 return;
204 } else if (cause instanceof RejectedExecutionException) {
205 log.error("Could not process message: queue full");
206 } else if (cause instanceof IOException) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900207 log.error("IOException occurred");
Daniel Parkbe6b6732016-11-11 15:52:19 +0900208 } else {
209 log.error("Error while processing message from switch {}", cause.getMessage());
210 }
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900211 channel.close();
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700212 }
213
214 private void setState(ChannelState state) {
215 this.state = state;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900216 if (state != INIT) {
217 log.debug(String.format(MSG_CHANNEL_STATE, channel.remoteAddress(), state.name()));
218 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700219 }
Daniel Parkbe6b6732016-11-11 15:52:19 +0900220
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900221 private void logErrorClose(OFErrorMsg errorMsg) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900222 log.error("{} from switch {} in state {}",
223 errorMsg,
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900224 ofSwitch.dpid(),
Daniel Parkbe6b6732016-11-11 15:52:19 +0900225 state);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900226 channel.close();
Daniel Parkbe6b6732016-11-11 15:52:19 +0900227 }
228
229 private void illegalMessageReceived(OFMessage ofMessage) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400230 log.warn("Controller should never send message {} to switch {} in current state {}",
231 ofMessage.getType(), ofSwitch.dpid(), state);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900232 }
233
234 private void unhandledMessageReceived(OFMessage ofMessage) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400235 log.warn("Unexpected message {} received for switch {} in state {}",
236 ofMessage.getType(), ofSwitch.dpid(), state);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900237 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700238}