ODL openflowjava和openflowplugin的启动流程,代码详解。

来源:互联网 发布:w7电脑网络出现感叹号 编辑:程序博客网 时间:2024/06/17 06:57


我们从南向北开始分析,首先看openflowjava工程,重点关注openflow-protocol-impl bundle。
首先查看该工程\src\main\yang目录下的yang文件,该文件指定了这个bundle启动的一些配置。
重点关注下面这段代码:
augment "/config:modules/config:module/config:configuration" {
case openflow-switch-connection-provider-impl {
when "/config:modules/config:module/config:type = 'openflow-switch-connection-provider-impl'";

leaf port { //openflow协议使用的端口,(of1.0 6633) (of1.3 6653)
description "local listening port";
type uint16;
mandatory true;
}
leaf address {//监听的ip
description "address of local listening interface";
type ietf-inet:ip-address;
}
leaf transport-protocol {//传输协议一般是tcp
description "Transport protocol used for communication.";
type of-config:transport-protocol;
mandatory true;
}
leaf switch-idle-timeout {//设备超时时间
description "idle timeout in [ms]";
type uint32;
mandatory true;
}
container tls {//安全传输层协议
leaf keystore {
description "keystore location";
type string;
}
leaf keystore-type {
description "keystore type (JKS or PKCS12)";
type of-config:keystore-type;
}
leaf keystore-path-type {
description "keystore path type (CLASSPATH or PATH)";
type of-config:path-type;
}
leaf keystore-password {
description "password protecting keystore";
type string;
}
leaf certificate-password {
description "password protecting certificate";
type string;
}
leaf truststore {
description "truststore location";
type string;
}
leaf truststore-type {
description "truststore type (JKS or PKCS12)";
type of-config:keystore-type;
}
leaf truststore-path-type {
description "truststore path type (CLASSPATH or PATH)";
type of-config:path-type;
}
leaf truststore-password {
description "password protecting truststore";
type string;
}
}
container threads {
leaf boss-threads {
type uint16;
}
leaf worker-threads {
type uint16;
}
}
leaf outbound-queue-size {
description "Sets size of ChannelOutboundQueue";
type uint16;
default 1024;
}
}
}

SwitchConnectionProviderModule为该bundle的启动类,关注creatInstance()方法:
public java.lang.AutoCloseable createInstance() {
LOG.info("SwitchConnectionProvider started.");
SwitchConnectionProviderImpl switchConnectionProviderImpl = new SwitchConnectionProviderImpl();
try {
ConnectionConfiguration connConfiguration = createConnectionConfiguration();
switchConnectionProviderImpl.setConfiguration(connConfiguration);
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
return switchConnectionProviderImpl;
}
可见其首先实例化了一个SwitchConnectionProviderImpl对象,该对象的构造方法如下:
/** Constructor */
public SwitchConnectionProviderImpl() {
serializerRegistry = new SerializerRegistryImpl();
serializerRegistry.init();
serializationFactory = new SerializationFactory();
serializationFactory.setSerializerTable(serializerRegistry);
deserializerRegistry = new DeserializerRegistryImpl();
deserializerRegistry.init();
deserializationFactory = new DeserializationFactory();
deserializationFactory.setRegistry(deserializerRegistry);
}
在该构造方法里主要完成,注册openflow消息的编解码工厂
例如:
version = EncodeConstants.OF13_VERSION_ID;
registryHelper = new CommonMessageRegistryHelper(version, serializerRegistry);
registryHelper.registerSerializer(BarrierInput.class, new BarrierInputMessageFactory());
registryHelper.registerSerializer(EchoInput.class, new EchoInputMessageFactory());
registryHelper.registerSerializer(EchoReplyInput.class, new EchoReplyInputMessageFactory());
registryHelper.registerSerializer(FlowModInput.class, new FlowModInputMessageFactory());
到此,openflow-protocol-impl启动完毕。
这时大家可能有疑问,这好像什么也没干啊,但通过查看openflow-protocol-spi中的yang文件发现,接口SwitchConnectionProvider作为一个服务被导出,而这个接口的实现正是前文实例化的SwitchConnectionProviderImpl对象,所以大胆猜测,引入接口SwitchConnectionProvider的bundle会继续调用接口SwitchConnectionProviderImpl实例。
而唯一可能调用该实例的bundle,应该位于openfllowplugin工程中。
查看openflowplugin工程的openflowplugin bundle中的yang文件openflow-plugin-cfg-impl.yang,可见其确实引入了SwitchConnectionProvider接口。
import openflow-switch-connection-provider 
还要注意该yang文件中的这段定义:
augment "/config:modules/config:module/config:configuration" {
case openflow-provider-impl {
when "/config:modules/config:module/config:type = 'openflow-provider-impl'";

container binding-aware-broker {
uses config:service-ref {
refine type {
mandatory true;
config:required-identity md-sal-binding:binding-broker-osgi-registry;
}
}
}
list openflow-switch-connection-provider {
uses config:service-ref {
refine type {
mandatory true;
config:required-identity openflow-switch-connection-provider:openflow-switch-connection-provider;
}
}
}
}
标黄的语句表明,openfllowplugin应该会使用多个SwitchConnectionProvider实例,通过分析openflowplugin-controller-config中的42-openflowplugin.xml文件可以得知,运行时会存在两个SwitchConnectionProvider实例分别监听6633和6653端口。
接下来查看openflowplugin 的启动类,ConfigurableOpenFlowProviderModule
@Override
public java.lang.AutoCloseable createInstance() {
pluginProvider = new OpenflowPluginProvider();
pluginProvider.setBroker(getBindingAwareBrokerDependency());
pluginProvider.setSwitchConnectionProviders(getOpenflowSwitchConnectionProviderDependency());
pluginProvider.initialization();
return pluginProvider;
}
这里面的getOpenflowSwitchConnectionProviderDependency()需要注意下,返回的是Collection<SwitchConnectionProvider> ,该Collection应该只有两个元素。
可见SwitchConnectionProvider的集合被set到了OpenflowPluginProvider的实例中。然后调用了OpenflowPluginProvider的初始化方法,如下:
public void initialization() {
messageCountProvider = new MessageSpyCounterImpl();
extensionConverterManager = new ExtensionConverterManagerImpl();
this.registerProvider();
}
在执行this.registerProvider()时,会调用OpenflowPluginProvider中的onSessionInitiated()方法
@Override
public void onSessionInitiated(ProviderContext session) {
LOG.debug("onSessionInitiated");
registrationManager = new SalRegistrationManager();
registrationManager.onSessionInitiated(session);
mdController = new MDController();
mdController.setSwitchConnectionProviders(switchConnectionProviders);
mdController.setMessageSpyCounter(messageCountProvider);
mdController.setExtensionConverterProvider(extensionConverterManager);
mdController.init();
mdController.start();
}
这段代码主要实现了:
获取notification服务,databroker服务,注册了session观察者SalRegistrationManager,
在MDController中注册openflow消息的translator,translate之后消息的poplistener(用于向md-sal发送notification)
最后调用的MDController的start()方法,是整个启动流程的关键,我们一步一步分析:
public void start() {
LOG.debug("starting ..");
LOG.debug("switchConnectionProvider: " + switchConnectionProviders);
// setup handler
SwitchConnectionHandlerImpl switchConnectionHandler = new SwitchConnectionHandlerImpl();
switchConnectionHandler.setMessageSpy(messageSpyCounter);

errorHandler = new ErrorHandlerSimpleImpl();

switchConnectionHandler.setErrorHandler(errorHandler);
switchConnectionHandler.init();

List<ListenableFuture<Boolean>> starterChain = new ArrayList<>(switchConnectionProviders.size());
for (SwitchConnectionProvider switchConnectionPrv : switchConnectionProviders) {
switchConnectionPrv.setSwitchConnectionHandler(switchConnectionHandler);
ListenableFuture<Boolean> isOnlineFuture = switchConnectionPrv.startup();
starterChain.add(isOnlineFuture);
}

Future<List<Boolean>> srvStarted = Futures.allAsList(starterChain);
}
首先,实例化了SwitchConnectionHandlerImpl,其构造方法如下:
public SwitchConnectionHandlerImpl() {
queueProcessor = new QueueProcessorLightImpl();

//TODO: implement shutdown invocation upon service stop event
spyPool = new ScheduledThreadPoolExecutor(1);
}
实例化了QueueProcessorLightImpl对象,该对象是以后处理openfllow消息的重要类,在此先不展开讲。
创建了一个ScheduledThreadPoolExecutor实例,这个实例是一个可以实现定时,延迟,重复执行任务的线程池,该线程池大小是1。

然后,在set了messageSpy和errorHandler之后调用了SwitchConnectionHandlerImpl的init()方法。
/**
* wire all up
*/
public void init() {
queueProcessor.setTranslatorMapping(OFSessionUtil.getTranslatorMap());
queueProcessor.setPopListenersMapping(OFSessionUtil.getPopListenerMapping());
queueProcessor.setMessageSpy(messageSpy);

queueProcessor.init();

spyPool.scheduleAtFixedRate(messageSpy, spyRate, spyRate, TimeUnit.SECONDS);
}
这里面的queueProcessor就是上一步实例化的QueueProcessorLightImpl对象,然后调用了QueueProcessorLightImpl的init()方法:
/**
* prepare queue
*/
public void init() {
int ticketQueueCapacity = 1500;
ticketQueue = new ArrayBlockingQueue<>(ticketQueueCapacity);
/*
* TODO FIXME - DOES THIS REALLY NEED TO BE CONCURRENT? Can we figure out
* a better lifecycle? Why does this have to be a Set?
*/
messageSources = new CopyOnWriteArraySet<>();

processorPool = new ThreadPoolLoggingExecutor(processingPoolSize, processingPoolSize, 0,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(ticketQueueCapacity),
"OFmsgProcessor");
// force blocking when pool queue is full
processorPool.setRejectedExecutionHandler(new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
}
});

harvesterPool = new ThreadPoolLoggingExecutor(1, 1, 0,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), "OFmsgHarvester");
finisherPool = new ThreadPoolLoggingExecutor(1, 1, 0,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), "OFmsgFinisher");
finisher = new TicketFinisherImpl(
ticketQueue, popListenersMapping);
finisherPool.execute(finisher);

harvester = new QueueKeeperHarvester<OfHeader>(this, messageSources);
harvesterPool.execute(harvester);

ticketProcessorFactory = new TicketProcessorFactoryImpl();
ticketProcessorFactory.setTranslatorMapping(translatorMapping);
ticketProcessorFactory.setSpy(messageSpy);
ticketProcessorFactory.setTicketFinisher(finisher);
}
在这个方法里实例化了3个线程池,ThreadPoolExecutor中各个参数的含义可以参考下面的帖子
http://www.cnblogs.com/dolphin0520/p/3932921.html
第一个processorPool,用来处理(主要是translate)收到的openflow消息
第二个harvesterPool ,用来处理openfllow的消息队列
第三个finisherPool, 用来发送处理后(translate之后)的openfllow消息
这三个的关系以后再说,接着回到之前的MDController的start()方法,应该运行到for循环这一步了
    for (SwitchConnectionProvider switchConnectionPrv : switchConnectionProviders) {
switchConnectionPrv.setSwitchConnectionHandler(switchConnectionHandler);
ListenableFuture<Boolean> isOnlineFuture = switchConnectionPrv.startup();
starterChain.add(isOnlineFuture);
}
在这终于使用openflow-protocol-impl这个bundle中的SwitchConnectionProvider对象了。重点看一下SwitchConnectionProvider的startup()方法:
@Override
public ListenableFuture<Boolean> startup() {
LOGGER.debug("Startup summoned");
serverFacade = createAndConfigureServer();

LOGGER.debug("Starting ..");
ListenableFuture<Boolean> result = null;
try {
if (serverFacade == null) {
throw new IllegalStateException("No server configured");
}
if (serverFacade.getIsOnlineFuture().isDone()) {
throw new IllegalStateException("Server already running");
}
if (switchConnectionHandler == null) {
throw new IllegalStateException("switchConnectionHandler is not set");
}
new Thread(serverFacade).start();
result = serverFacade.getIsOnlineFuture();
} catch (Exception e) {
SettableFuture<Boolean> exResult = SettableFuture.create();
exResult.setException(e);
result = exResult;
}
return result;
}

/**
* @return
*/
private ServerFacade createAndConfigureServer() {
LOGGER.debug("Configuring ..");
ServerFacade server = null;
ChannelInitializerFactory factory = new ChannelInitializerFactory();
factory.setSwitchConnectionHandler(switchConnectionHandler);
factory.setSwitchIdleTimeout(connConfig.getSwitchIdleTimeout());
factory.setTlsConfig(connConfig.getTlsConfiguration());
factory.setSerializationFactory(serializationFactory);
factory.setDeserializationFactory(deserializationFactory);
factory.setOutboundQueueSize(connConfig.getOutboundQueueSize());
TransportProtocol transportProtocol = (TransportProtocol) connConfig.getTransferProtocol();
if (transportProtocol.equals(TransportProtocol.TCP) || transportProtocol.equals(TransportProtocol.TLS)) {
server = new TcpHandler(connConfig.getAddress(), connConfig.getPort());
((TcpHandler) server).setChannelInitializer(factory.createPublishingChannelInitializer());
} else {
server = new UdpHandler(connConfig.getAddress(), connConfig.getPort());
((UdpHandler) server).setChannelInitializer(factory.createUdpChannelInitializer());
}
server.setThreadConfig(connConfig.getThreadConfiguration());
return server;
}
这个方法的功能简单来说就是创建一个Tcp或Udp的server来监听指定的端口,从目前的配置文件来看,创建的都是Tcp的Server端。
到此整个openflow协议栈完全启动,controller与设备如何建立连接,以及如何接收和发送openflow消息,请听下回分解吧。

我们从南向北开始分析,首先看openflowjava工程,重点关注openflow-protocol-impl bundle。
首先查看该工程\src\main\yang目录下的yang文件,该文件指定了这个bundle启动的一些配置。
重点关注下面这段代码:
augment "/config:modules/config:module/config:configuration" {
case openflow-switch-connection-provider-impl {
when "/config:modules/config:module/config:type = 'openflow-switch-connection-provider-impl'";

leaf port { //openflow协议使用的端口,(of1.0 6633) (of1.3 6653)
description "local listening port";
type uint16;
mandatory true;
}
leaf address {//监听的ip
description "address of local listening interface";
type ietf-inet:ip-address;
}
leaf transport-protocol {//传输协议一般是tcp
description "Transport protocol used for communication.";
type of-config:transport-protocol;
mandatory true;
}
leaf switch-idle-timeout {//设备超时时间
description "idle timeout in [ms]";
type uint32;
mandatory true;
}
container tls {//安全传输层协议
leaf keystore {
description "keystore location";
type string;
}
leaf keystore-type {
description "keystore type (JKS or PKCS12)";
type of-config:keystore-type;
}
leaf keystore-path-type {
description "keystore path type (CLASSPATH or PATH)";
type of-config:path-type;
}
leaf keystore-password {
description "password protecting keystore";
type string;
}
leaf certificate-password {
description "password protecting certificate";
type string;
}
leaf truststore {
description "truststore location";
type string;
}
leaf truststore-type {
description "truststore type (JKS or PKCS12)";
type of-config:keystore-type;
}
leaf truststore-path-type {
description "truststore path type (CLASSPATH or PATH)";
type of-config:path-type;
}
leaf truststore-password {
description "password protecting truststore";
type string;
}
}
container threads {
leaf boss-threads {
type uint16;
}
leaf worker-threads {
type uint16;
}
}
leaf outbound-queue-size {
description "Sets size of ChannelOutboundQueue";
type uint16;
default 1024;
}
}
}

SwitchConnectionProviderModule为该bundle的启动类,关注creatInstance()方法:
public java.lang.AutoCloseable createInstance() {
LOG.info("SwitchConnectionProvider started.");
SwitchConnectionProviderImpl switchConnectionProviderImpl = new SwitchConnectionProviderImpl();
try {
ConnectionConfiguration connConfiguration = createConnectionConfiguration();
switchConnectionProviderImpl.setConfiguration(connConfiguration);
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
return switchConnectionProviderImpl;
}
可见其首先实例化了一个SwitchConnectionProviderImpl对象,该对象的构造方法如下:
/** Constructor */
public SwitchConnectionProviderImpl() {
serializerRegistry = new SerializerRegistryImpl();
serializerRegistry.init();
serializationFactory = new SerializationFactory();
serializationFactory.setSerializerTable(serializerRegistry);
deserializerRegistry = new DeserializerRegistryImpl();
deserializerRegistry.init();
deserializationFactory = new DeserializationFactory();
deserializationFactory.setRegistry(deserializerRegistry);
}
在该构造方法里主要完成,注册openflow消息的编解码工厂
例如:
version = EncodeConstants.OF13_VERSION_ID;
registryHelper = new CommonMessageRegistryHelper(version, serializerRegistry);
registryHelper.registerSerializer(BarrierInput.class, new BarrierInputMessageFactory());
registryHelper.registerSerializer(EchoInput.class, new EchoInputMessageFactory());
registryHelper.registerSerializer(EchoReplyInput.class, new EchoReplyInputMessageFactory());
registryHelper.registerSerializer(FlowModInput.class, new FlowModInputMessageFactory());
到此,openflow-protocol-impl启动完毕。
这时大家可能有疑问,这好像什么也没干啊,但通过查看openflow-protocol-spi中的yang文件发现,接口SwitchConnectionProvider作为一个服务被导出,而这个接口的实现正是前文实例化的SwitchConnectionProviderImpl对象,所以大胆猜测,引入接口SwitchConnectionProvider的bundle会继续调用接口SwitchConnectionProviderImpl实例。
而唯一可能调用该实例的bundle,应该位于openfllowplugin工程中。
查看openflowplugin工程的openflowplugin bundle中的yang文件openflow-plugin-cfg-impl.yang,可见其确实引入了SwitchConnectionProvider接口。
import openflow-switch-connection-provider 
还要注意该yang文件中的这段定义:
augment "/config:modules/config:module/config:configuration" {
case openflow-provider-impl {
when "/config:modules/config:module/config:type = 'openflow-provider-impl'";

container binding-aware-broker {
uses config:service-ref {
refine type {
mandatory true;
config:required-identity md-sal-binding:binding-broker-osgi-registry;
}
}
}
list openflow-switch-connection-provider {
uses config:service-ref {
refine type {
mandatory true;
config:required-identity openflow-switch-connection-provider:openflow-switch-connection-provider;
}
}
}
}
标黄的语句表明,openfllowplugin应该会使用多个SwitchConnectionProvider实例,通过分析openflowplugin-controller-config中的42-openflowplugin.xml文件可以得知,运行时会存在两个SwitchConnectionProvider实例分别监听6633和6653端口。
接下来查看openflowplugin 的启动类,ConfigurableOpenFlowProviderModule
@Override
public java.lang.AutoCloseable createInstance() {
pluginProvider = new OpenflowPluginProvider();
pluginProvider.setBroker(getBindingAwareBrokerDependency());
pluginProvider.setSwitchConnectionProviders(getOpenflowSwitchConnectionProviderDependency());
pluginProvider.initialization();
return pluginProvider;
}
这里面的getOpenflowSwitchConnectionProviderDependency()需要注意下,返回的是Collection<SwitchConnectionProvider> ,该Collection应该只有两个元素。
可见SwitchConnectionProvider的集合被set到了OpenflowPluginProvider的实例中。然后调用了OpenflowPluginProvider的初始化方法,如下:
public void initialization() {
messageCountProvider = new MessageSpyCounterImpl();
extensionConverterManager = new ExtensionConverterManagerImpl();
this.registerProvider();
}
在执行this.registerProvider()时,会调用OpenflowPluginProvider中的onSessionInitiated()方法
@Override
public void onSessionInitiated(ProviderContext session) {
LOG.debug("onSessionInitiated");
registrationManager = new SalRegistrationManager();
registrationManager.onSessionInitiated(session);
mdController = new MDController();
mdController.setSwitchConnectionProviders(switchConnectionProviders);
mdController.setMessageSpyCounter(messageCountProvider);
mdController.setExtensionConverterProvider(extensionConverterManager);
mdController.init();
mdController.start();
}
这段代码主要实现了:
获取notification服务,databroker服务,注册了session观察者SalRegistrationManager,
在MDController中注册openflow消息的translator,translate之后消息的poplistener(用于向md-sal发送notification)
最后调用的MDController的start()方法,是整个启动流程的关键,我们一步一步分析:
public void start() {
LOG.debug("starting ..");
LOG.debug("switchConnectionProvider: " + switchConnectionProviders);
// setup handler
SwitchConnectionHandlerImpl switchConnectionHandler = new SwitchConnectionHandlerImpl();
switchConnectionHandler.setMessageSpy(messageSpyCounter);

errorHandler = new ErrorHandlerSimpleImpl();

switchConnectionHandler.setErrorHandler(errorHandler);
switchConnectionHandler.init();

List<ListenableFuture<Boolean>> starterChain = new ArrayList<>(switchConnectionProviders.size());
for (SwitchConnectionProvider switchConnectionPrv : switchConnectionProviders) {
switchConnectionPrv.setSwitchConnectionHandler(switchConnectionHandler);
ListenableFuture<Boolean> isOnlineFuture = switchConnectionPrv.startup();
starterChain.add(isOnlineFuture);
}

Future<List<Boolean>> srvStarted = Futures.allAsList(starterChain);
}
首先,实例化了SwitchConnectionHandlerImpl,其构造方法如下:
public SwitchConnectionHandlerImpl() {
queueProcessor = new QueueProcessorLightImpl();

//TODO: implement shutdown invocation upon service stop event
spyPool = new ScheduledThreadPoolExecutor(1);
}
实例化了QueueProcessorLightImpl对象,该对象是以后处理openfllow消息的重要类,在此先不展开讲。
创建了一个ScheduledThreadPoolExecutor实例,这个实例是一个可以实现定时,延迟,重复执行任务的线程池,该线程池大小是1。

然后,在set了messageSpy和errorHandler之后调用了SwitchConnectionHandlerImpl的init()方法。
/**
* wire all up
*/
public void init() {
queueProcessor.setTranslatorMapping(OFSessionUtil.getTranslatorMap());
queueProcessor.setPopListenersMapping(OFSessionUtil.getPopListenerMapping());
queueProcessor.setMessageSpy(messageSpy);

queueProcessor.init();

spyPool.scheduleAtFixedRate(messageSpy, spyRate, spyRate, TimeUnit.SECONDS);
}
这里面的queueProcessor就是上一步实例化的QueueProcessorLightImpl对象,然后调用了QueueProcessorLightImpl的init()方法:
/**
* prepare queue
*/
public void init() {
int ticketQueueCapacity = 1500;
ticketQueue = new ArrayBlockingQueue<>(ticketQueueCapacity);
/*
* TODO FIXME - DOES THIS REALLY NEED TO BE CONCURRENT? Can we figure out
* a better lifecycle? Why does this have to be a Set?
*/
messageSources = new CopyOnWriteArraySet<>();

processorPool = new ThreadPoolLoggingExecutor(processingPoolSize, processingPoolSize, 0,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(ticketQueueCapacity),
"OFmsgProcessor");
// force blocking when pool queue is full
processorPool.setRejectedExecutionHandler(new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
}
});

harvesterPool = new ThreadPoolLoggingExecutor(1, 1, 0,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), "OFmsgHarvester");
finisherPool = new ThreadPoolLoggingExecutor(1, 1, 0,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), "OFmsgFinisher");
finisher = new TicketFinisherImpl(
ticketQueue, popListenersMapping);
finisherPool.execute(finisher);

harvester = new QueueKeeperHarvester<OfHeader>(this, messageSources);
harvesterPool.execute(harvester);

ticketProcessorFactory = new TicketProcessorFactoryImpl();
ticketProcessorFactory.setTranslatorMapping(translatorMapping);
ticketProcessorFactory.setSpy(messageSpy);
ticketProcessorFactory.setTicketFinisher(finisher);
}
在这个方法里实例化了3个线程池,ThreadPoolExecutor中各个参数的含义可以参考下面的帖子
http://www.cnblogs.com/dolphin0520/p/3932921.html
第一个processorPool,用来处理(主要是translate)收到的openflow消息
第二个harvesterPool ,用来处理openfllow的消息队列
第三个finisherPool, 用来发送处理后(translate之后)的openfllow消息
这三个的关系以后再说,接着回到之前的MDController的start()方法,应该运行到for循环这一步了
    for (SwitchConnectionProvider switchConnectionPrv : switchConnectionProviders) {
switchConnectionPrv.setSwitchConnectionHandler(switchConnectionHandler);
ListenableFuture<Boolean> isOnlineFuture = switchConnectionPrv.startup();
starterChain.add(isOnlineFuture);
}
在这终于使用openflow-protocol-impl这个bundle中的SwitchConnectionProvider对象了。重点看一下SwitchConnectionProvider的startup()方法:
@Override
public ListenableFuture<Boolean> startup() {
LOGGER.debug("Startup summoned");
serverFacade = createAndConfigureServer();

LOGGER.debug("Starting ..");
ListenableFuture<Boolean> result = null;
try {
if (serverFacade == null) {
throw new IllegalStateException("No server configured");
}
if (serverFacade.getIsOnlineFuture().isDone()) {
throw new IllegalStateException("Server already running");
}
if (switchConnectionHandler == null) {
throw new IllegalStateException("switchConnectionHandler is not set");
}
new Thread(serverFacade).start();
result = serverFacade.getIsOnlineFuture();
} catch (Exception e) {
SettableFuture<Boolean> exResult = SettableFuture.create();
exResult.setException(e);
result = exResult;
}
return result;
}

/**
* @return
*/
private ServerFacade createAndConfigureServer() {
LOGGER.debug("Configuring ..");
ServerFacade server = null;
ChannelInitializerFactory factory = new ChannelInitializerFactory();
factory.setSwitchConnectionHandler(switchConnectionHandler);
factory.setSwitchIdleTimeout(connConfig.getSwitchIdleTimeout());
factory.setTlsConfig(connConfig.getTlsConfiguration());
factory.setSerializationFactory(serializationFactory);
factory.setDeserializationFactory(deserializationFactory);
factory.setOutboundQueueSize(connConfig.getOutboundQueueSize());
TransportProtocol transportProtocol = (TransportProtocol) connConfig.getTransferProtocol();
if (transportProtocol.equals(TransportProtocol.TCP) || transportProtocol.equals(TransportProtocol.TLS)) {
server = new TcpHandler(connConfig.getAddress(), connConfig.getPort());
((TcpHandler) server).setChannelInitializer(factory.createPublishingChannelInitializer());
} else {
server = new UdpHandler(connConfig.getAddress(), connConfig.getPort());
((UdpHandler) server).setChannelInitializer(factory.createUdpChannelInitializer());
}
server.setThreadConfig(connConfig.getThreadConfiguration());
return server;
}
这个方法的功能简单来说就是创建一个Tcp或Udp的server来监听指定的端口,从目前的配置文件来看,创建的都是Tcp的Server端。
到此整个openflow协议栈完全启动,controller与设备如何建立连接,以及如何接收和发送openflow消息,请听下回分解吧。

0 0
原创粉丝点击