blob: 3853073710e0701edb9f2aade46a92bd391cf44d [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 Moon90163ba2016-10-12 13:35:14 -070018import io.netty.channel.ChannelDuplexHandler;
19import io.netty.channel.ChannelHandlerContext;
Daniel Parkbe6b6732016-11-11 15:52:19 +090020import io.netty.handler.timeout.ReadTimeoutException;
21import org.onlab.osgi.DefaultServiceDirectory;
22import org.onlab.osgi.ServiceDirectory;
23import org.onosproject.incubator.net.virtual.VirtualNetworkService;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070024import org.onosproject.ofagent.api.OFSwitch;
Daniel Parkbe6b6732016-11-11 15:52:19 +090025import org.projectfloodlight.openflow.protocol.OFErrorMsg;
26import org.projectfloodlight.openflow.protocol.OFFactories;
27import org.projectfloodlight.openflow.protocol.OFFactory;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070028import org.projectfloodlight.openflow.protocol.OFMessage;
Daniel Parkbe6b6732016-11-11 15:52:19 +090029import org.projectfloodlight.openflow.protocol.OFVersion;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070030import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
Daniel Parkbe6b6732016-11-11 15:52:19 +090033import java.io.IOException;
34import java.nio.channels.ClosedChannelException;
35import java.util.List;
36import java.util.concurrent.RejectedExecutionException;
37
Hyunsun Moon90163ba2016-10-12 13:35:14 -070038/**
39 * Implementation of OpenFlow channel handler.
40 * It processes OpenFlow message according to the channel state.
41 */
42public final class OFChannelHandler extends ChannelDuplexHandler {
43
44 private final Logger log = LoggerFactory.getLogger(getClass());
45 private final OFSwitch ofSwitch;
46
Daniel Parkbe6b6732016-11-11 15:52:19 +090047 private ChannelHandlerContext ctx;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070048 private ChannelState state;
Daniel Parkbe6b6732016-11-11 15:52:19 +090049 protected static final OFFactory FACTORY = OFFactories.getFactory(OFVersion.OF_13);
50 protected VirtualNetworkService vNetService;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070051
Daniel Parkbe6b6732016-11-11 15:52:19 +090052 enum ChannelState {
Hyunsun Moon90163ba2016-10-12 13:35:14 -070053
54 INIT {
55 @Override
56 void processOFMessage(final OFChannelHandler handler,
57 final OFMessage msg) {
58 // TODO implement
59 }
60 },
61 WAIT_HELLO {
62 @Override
63 void processOFMessage(final OFChannelHandler handler,
64 final OFMessage msg) {
Daniel Parkbe6b6732016-11-11 15:52:19 +090065
66 switch (msg.getType()) {
67 case HELLO:
68 handler.setState(ChannelState.WAIT_FEATURE_REQUEST);
69 break;
70 default:
71 handler.illegalMessageReceived(msg);
72 break;
73 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -070074 }
75 },
76 WAIT_FEATURE_REQUEST {
77 @Override
78 void processOFMessage(final OFChannelHandler handler,
79 final OFMessage msg) {
Daniel Parkbe6b6732016-11-11 15:52:19 +090080
81 switch (msg.getType()) {
82 case FEATURES_REQUEST:
83 handler.ofSwitch.processFeaturesRequest(handler.ctx.channel(), msg);
84 handler.setState(ChannelState.ESTABLISHED);
85 break;
86 case ECHO_REQUEST:
87 handler.ofSwitch.processEchoRequest(handler.ctx.channel(), msg);
88 break;
89 case ERROR:
90 handler.logErrorClose(handler.ctx, (OFErrorMsg) msg);
91 break;
92 default:
93 handler.illegalMessageReceived(msg);
94 break;
95
96 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -070097 }
98 },
99 ESTABLISHED {
100 @Override
101 void processOFMessage(final OFChannelHandler handler,
102 final OFMessage msg) {
103 // TODO implement
104 // TODO add this channel to ofSwitch role service
Daniel Parkbe6b6732016-11-11 15:52:19 +0900105 switch (msg.getType()) {
106 case STATS_REQUEST:
107 //TODO implement
108 //TODO: use vNetService to build OFPortDesc.
109 break;
110 case SET_CONFIG:
111 //TODO implement
112 break;
113 case GET_CONFIG_REQUEST:
114 //TODO implement
115 break;
116 case BARRIER_REQUEST:
117 //TODO implement
118 break;
119 case ECHO_REQUEST:
120 handler.ofSwitch.processEchoRequest(handler.ctx.channel(), msg);
121 break;
122 case ERROR:
123 handler.logErrorClose(handler.ctx, (OFErrorMsg) msg);
124 break;
125 default:
126 handler.unhandledMessageReceived(msg);
127 break;
128 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700129 }
130 };
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700131 abstract void processOFMessage(final OFChannelHandler handler,
132 final OFMessage msg);
133 }
134
135 /**
136 * Default constructor.
137 *
138 * @param ofSwitch openflow switch that owns this channel
139 */
140 public OFChannelHandler(OFSwitch ofSwitch) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900141 super();
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700142 this.ofSwitch = ofSwitch;
Daniel Parkbe6b6732016-11-11 15:52:19 +0900143
144 setState(ChannelState.INIT);
145
146 ServiceDirectory services = new DefaultServiceDirectory();
147 vNetService = services.get(VirtualNetworkService.class);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700148 }
149
150 @Override
151 public void channelActive(ChannelHandlerContext ctx) throws Exception {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900152 this.ctx = ctx;
153 log.debug("Channel Active. Send OF_13 Hello to {}", ctx.channel().remoteAddress());
154
155 try {
156 ofSwitch.sendOfHello(ctx.channel());
157 setState(ChannelState.WAIT_HELLO);
158 } catch (Throwable cause) {
159 log.error("Exception occured because of{}", cause.getMessage());
160 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700161 }
162
163 @Override
164 public void channelRead(ChannelHandlerContext ctx, Object msg)
165 throws Exception {
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700166
Daniel Parkbe6b6732016-11-11 15:52:19 +0900167 try {
168 if (msg instanceof List) {
169 ((List) msg).forEach(ofm -> {
170 state.processOFMessage(this, (OFMessage) ofm);
171 });
172 } else {
173 state.processOFMessage(this, (OFMessage) msg);
174 }
175 } catch (Throwable cause) {
176 log.error("Exception occured {}", cause.getMessage());
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700177 }
Daniel Parkbe6b6732016-11-11 15:52:19 +0900178
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700179 }
180
181 @Override
182 public void channelReadComplete(ChannelHandlerContext ctx)
183 throws Exception {
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700184 }
185
186 @Override
187 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
Daniel Parkbe6b6732016-11-11 15:52:19 +0900188 if (cause instanceof ReadTimeoutException) {
189 log.error("Connection closed because of ReadTimeoutException {}", cause.getMessage());
190 } else if (cause instanceof ClosedChannelException) {
191 log.error("ClosedChannelException occured");
192 return;
193 } else if (cause instanceof RejectedExecutionException) {
194 log.error("Could not process message: queue full");
195 } else if (cause instanceof IOException) {
196 log.error("IOException occured");
197 } else {
198 log.error("Error while processing message from switch {}", cause.getMessage());
199 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700200 ctx.close();
201 }
202
203 private void setState(ChannelState state) {
204 this.state = state;
205 }
Daniel Parkbe6b6732016-11-11 15:52:19 +0900206
207 private void logErrorClose(ChannelHandlerContext ctx, OFErrorMsg errorMsg) {
208 log.error("{} from switch {} in state {}",
209 errorMsg,
210 ofSwitch.device().id().toString(),
211 state);
212
213 log.error("Disconnecting...");
214 ctx.close();
215 }
216
217 private void illegalMessageReceived(OFMessage ofMessage) {
218 log.warn("Controller should never send this message {} in current state {}",
219 ofMessage.getType().toString(),
220 state);
221 }
222
223 private void unhandledMessageReceived(OFMessage ofMessage) {
224 log.warn("Unhandled message {} received in state {}. Ignored",
225 ofMessage.getType().toString(),
226 state);
227 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700228}