/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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 net.floodlightcontroller.core.internal;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.List;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.types.U32;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.floodlightcontroller.core.internal.IOFSwitchManager;
import net.floodlightcontroller.core.internal.HandshakeTimeoutHandler;
import net.floodlightcontroller.core.internal.INewOFConnectionListener;
import net.floodlightcontroller.core.internal.OFChannelHandler;
import net.floodlightcontroller.debugcounter.IDebugCounterService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.Timer;
/**
* Creates a ChannelPipeline for a server-side openflow channel
* @author readams, sovietaced, rizard, andi-bigswitch
*/
public class OFChannelInitializer extends ChannelInitializer<Channel> {
private static final Logger log = LoggerFactory.getLogger(OFChannelInitializer.class);
private IOFSwitchManager switchManager;
private INewOFConnectionListener connectionListener;
private Timer timer;
private IDebugCounterService debugCounters;
private String keyStore;
private String keyStorePassword;
private OFFactory defaultFactory;
private List<U32> ofBitmaps;
public OFChannelInitializer(IOFSwitchManager switchManager,
INewOFConnectionListener connectionListener,
IDebugCounterService debugCounters,
Timer timer,
List<U32> ofBitmaps,
OFFactory defaultFactory,
String keyStore,
String keyStorePassword) {
super();
this.switchManager = switchManager;
this.connectionListener = connectionListener;
this.timer = timer;
this.debugCounters = debugCounters;
this.defaultFactory = defaultFactory;
this.ofBitmaps = ofBitmaps;
this.keyStore = keyStore;
this.keyStorePassword = keyStorePassword;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
OFChannelHandler handler = new OFChannelHandler(
switchManager,
connectionListener,
pipeline,
debugCounters,
timer,
ofBitmaps,
defaultFactory);
if (keyStore != null && keyStorePassword != null) {
try {
/* Set up factories and stores. */
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore tmpKS = null;
tmFactory.init(tmpKS);
/* Use keystore/pass defined in properties file. */
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStore), keyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keyStorePassword.toCharArray());
KeyManager[] km = kmf.getKeyManagers();
TrustManager[] tm = tmFactory.getTrustManagers();
/* Set up SSL prereqs for Netty. */
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(km, tm, null);
SSLEngine sslEngine = sslContext.createSSLEngine();
/* We are the server and we will create secure sessions. */
sslEngine.setUseClientMode(false);
sslEngine.setEnableSessionCreation(true);
/* These are redundant (default), but for clarity... */
sslEngine.setEnabledProtocols(sslEngine.getSupportedProtocols());
sslEngine.setEnabledCipherSuites(sslEngine.getSupportedCipherSuites());
/* First, decrypt w/handler+engine; then, proceed with rest of handlers. */
pipeline.addLast(PipelineHandler.SSL_TLS_ENCODER_DECODER, new SslHandler(sslEngine));
log.info("SSL OpenFlow socket initialized and handler ready for switch.");
} catch (Exception e) { /* There are lots of possible exceptions to catch, so this should get them all. */
log.error("Exception initializing SSL OpenFlow socket: {}", e.getMessage());
throw e; /* If we wanted secure but didn't get it, we should bail. */
}
}
pipeline.addLast(PipelineHandler.OF_MESSAGE_DECODER,
new OFMessageDecoder());
pipeline.addLast(PipelineHandler.OF_MESSAGE_ENCODER,
new OFMessageEncoder());
pipeline.addLast(PipelineHandler.MAIN_IDLE,
new IdleStateHandler(PipelineIdleReadTimeout.MAIN,
PipelineIdleWriteTimeout.MAIN,
0));
pipeline.addLast(PipelineHandler.READ_TIMEOUT, new ReadTimeoutHandler(30));
pipeline.addLast(PipelineHandler.CHANNEL_HANDSHAKE_TIMEOUT,
new HandshakeTimeoutHandler(
handler,
timer,
PipelineHandshakeTimeout.CHANNEL));
pipeline.addLast(PipelineHandler.CHANNEL_HANDLER, handler);
}
public static class PipelineHandler {
public final static String CHANNEL_HANDSHAKE_TIMEOUT = "channelhandshaketimeout";
public final static String SWITCH_HANDSHAKE_TIMEOUT = "switchhandshaketimeout";
public final static String CHANNEL_HANDLER = "channelhandler";
public final static String MAIN_IDLE = "mainidle";
public final static String AUX_IDLE = "auxidle";
public final static String OF_MESSAGE_DECODER = "ofmessagedecoder";
public final static String OF_MESSAGE_ENCODER = "ofmessageencoder";
public final static String READ_TIMEOUT = "readtimeout";
public final static String SSL_TLS_ENCODER_DECODER = "ofsecurechannelencoderdecoder"; }
/**
* Timeouts for parts of the handshake, in seconds
*/
public static class PipelineHandshakeTimeout {
final static int CHANNEL = 10;
public final static int SWITCH = 30;
}
/**
* Timeouts for writes on connections, in seconds
*/
public static class PipelineIdleWriteTimeout {
final static int MAIN = 2;
public final static int AUX = 15;
}
/**
* Timeouts for reads on connections, in seconds
*/
public static class PipelineIdleReadTimeout {
final static int MAIN = 3 * PipelineIdleWriteTimeout.MAIN;
public final static int AUX = 3 * PipelineIdleWriteTimeout.AUX;
}
}