Openflow Plugin学习笔记3
MDController.java 中的start方法,创建了SwitchConnectionHandlerImpl实例
SwitchConnectionHandlerImpl switchConnectionHandler = new SwitchConnectionHandlerImpl();
在SwitchConnectionHandlerImpl从命名理解即为交换机连接处理,在其构造方法中创建了QueueProcessorLightImpl实例。随后在start方法中调用了init方法对SwitchConnectionHandlerImpl进行初始化,该过程中传递给OF协议消息处理的上下行处理器,同时调用了QueueProcessorLightImpl的init方法,该方法创建了3个线程池,分别是processorPool,harvesterPool,finisherPool,用来处理消息,传递消息及处理消息处理结果。
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); // OF消息处理结果将从ticketQueue中获取,目前由于为空,因此处于阻塞状态
finisherPool.execute(finisher);
harvester = new QueueKeeperHarvester<OfHeader>(this, messageSources);
harvesterPool.execute(harvester);
ticketProcessorFactory = new TicketProcessorFactoryImpl(); // OF消息处理工厂
ticketProcessorFactory.setTranslatorMapping(translatorMapping);
ticketProcessorFactory.setSpy(messageSpy);
ticketProcessorFactory.setTicketFinisher(finisher);
}
其中harvester是串联起前后消息传递的重要手段,如下
harvester = new QueueKeeperHarvester<OfHeader>(this, messageSources);
创建给harvest时,传入的参数分别是QueueProcessorLightImpl实例本身与一个装载OF消息的集合,harsvert从集合中取出单个消息进入QueueProcessorLightImpl实例的ticket处理流程中。如下:
boolean starving = true;
for (QueueKeeper<IN> source : messageSources) {
QueueItem<IN> qItem = source.poll();
if (qItem != null) {
starving = false;
enqueuer.enqueueQueueItem(qItem); // 调用即为QueueProcessorLightImpl中的enqueueQueueItem方法
}
}
QueueProcessorLightImpl中enqueueQueueItem方法如下:
@Override
public void enqueueQueueItem(QueueItem<OfHeader> queueItem) {
messageSpy.spyMessage(queueItem.getMessage(), STATISTIC_GROUP.FROM_SWITCH_ENQUEUED);
TicketImpl<OfHeader, DataObject> ticket = new TicketImpl<>(); // 输入为OF消息,输出为MD-SAL消息
ticket.setConductor(queueItem.getConnectionConductor());
ticket.setMessage(queueItem.getMessage());
ticket.setQueueType(queueItem.getQueueType());
LOG.trace("ticket scheduling: {}, ticket: {}",
queueItem.getMessage().getImplementedInterface().getSimpleName(),
System.identityHashCode(queueItem));
scheduleTicket(ticket); // 进入线程处理
}
scheduleTicket方法将根据queue类型来选择线程,关于queue类型可参见《OpenDaylight OpenFlow Plugin 过载保护》,如下:
private void scheduleTicket(Ticket<OfHeader, DataObject> ticket) {
switch (ticket.getQueueType()) {
case DEFAULT: // 处理非pktin消息
Runnable ticketProcessor = ticketProcessorFactory.createProcessor(ticket); // 创建消息处理任务
processorPool.execute(ticketProcessor); // 放入处理线程池
try {
ticketQueue.put(ticket); // 结果放入队列
} catch (InterruptedException e) {
LOG.warn("enqeueue of unordered message ticket failed", e);
}
break;
case UNORDERED: // 处理pktin消息
Runnable ticketProcessorSync = ticketProcessorFactory.createSyncProcessor(ticket);
processorPool.execute(ticketProcessorSync);
break;
default:
LOG.warn("unsupported enqueue type: {}", ticket.getQueueType());
}
}
消息处理如下:
Runnable ticketProcessor = new Runnable() {
@Override
public void run() {
LOG.debug("message received, type: {}", ticket.getMessage().getImplementedInterface().getSimpleName());
List<DataObject> translate;
try {
translate = translate(ticket); // 翻译OF消息
ticket.getResult().set(translate); // 异步结果
ticket.setDirectResult(translate); // 直接返回结果
// spying on result
if (spy != null) {
spy.spyIn(ticket.getMessage());
for (DataObject outMessage : translate) {
spy.spyOut(outMessage);
}
}
} catch (Exception e) {
LOG.warn("translation problem: {}", e.getMessage());
ticket.getResult().setException(e);
}
LOG.debug("message processing done (type: {}, ticket: {})",
ticket.getMessage().getImplementedInterface().getSimpleName(),
System.identityHashCode(ticket));
}
};
Openflow Plugin学习笔记3的更多相关文章
- Openflow Plugin学习笔记2
OpenDaylight OpenFlow Plugin 过载保护 过载保护 OF Plugin中的过载保护按如下流程工作: ConnectionConductor将消息送入队列,是最靠近OFJava ...
- Openflow Plugin学习笔记1
主入口 ConfigurableOpenFlowProviderModule是OpenFlowPlugin中启动加载的入口,如下: @Override public java.lang.AutoClo ...
- OpenFlow Switch学习笔记(五)——Group Table、Meter Table及Counters
本文主要详述OpenFlow Switch的另外两个主要组件——Group Table和Meter Table,它们在整个OpenFlow Swtich Processing中也起到了重要作用. 1. ...
- OpenFlow Switch学习笔记(四)——Matching
这次我们着重详述来自于网络中的数据包在OpenFlow Switch中与Flow Entries的具体匹配过程,以及当出现Table Miss时的处理方式,下面就将从这两方面说起. 1.Matchin ...
- OpenFlow Switch学习笔记(一)——基础概念
OpenFlow Switch v1.4.0规范是在2013年10月14号发布,规范涵盖了OpenFlow Switch各个组件的功能定义.Controller与Switch之间的通信协议Open F ...
- OpenFlow Switch学习笔记(七)——Matching Fields
Matching Fields in_port=port Matches OpenFlow port port dl_vlan=vlan Matches IEEE 802.1q Virtual LAN ...
- OpenFlow Switch学习笔记(六)——Instructions和Actions
本文主要重点讨论OpenFlow Switch规范的指令集,它们深刻影响着数据包在Switch中的处理行为,下面开始从以下几个部分谈起. 1.Instructions 每一个Flow Entry里都包 ...
- OpenFlow Switch学习笔记(三)——Flow Tables
这次我们主要讨论下OpenFlow Switch的核心组件之一——Flow Tables,以了解其内部的 matching 以及 action handling 机制.下文将会分为几个部分来逐步详述O ...
- OpenFlow Switch学习笔记(二)——OpenFlow Ports
OpenFlow Ports是OpenFlow Switch与剩余网络之间传递Packet的网络接口.OpenFlow Switches之间通过OpenFlow Ports彼此相互逻辑连接.一个Ope ...
随机推荐
- php in_array()优化
开年首篇文章,后天上班了,正在调整状态.年前室友问我一段程序效率问题,刚好来研究下!该函数是关于判断域名字符串是否是单拼域名.双拼域名.三拼域名...多拼域名问题: //原始程序function pi ...
- C# 调用 taskkill命令结束服务进程
获取服务映像名称 windows服务安装后会在注册表中存储服务信息,路径是HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\[服务名称] 通过I ...
- 多线程-Thread的run()与start()的区别
总结: 1) start: 用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码.通过调用Thread类的start()方法来启动一个线程,这 ...
- Cron表达式简单的介绍
1.Cron是什么,用来做什么的 根据百度百科的解释:计划任务,是任务在约定的时间执行已经计划好的工作,这是表面的意思.在Linux中,我们经常用到 cron 服务器来完成这项工作.cron服务器可以 ...
- 多线程同步与并发访问共享资源工具—Lock、Monitor、Mutex、Semaphore
“线程同步”的含义 当一个进程启动了多个线程时,如果需要控制这些线程的推进顺序(比如A线程必须等待B和C线程执行完毕之后才能继续执行),则称这些线程需要进行“线程同步(thread synchro ...
- 【模考】2018.04.08 Travel
Description 有N个人出去旅行,第i个人去A国有Ai种游玩方式,去B国有Bi种游玩方式,问至少有C个人去A国的情况下,所有人的游玩方式有多少种不同的可能. 两种所有人的游玩方式不同当且仅当存 ...
- Unity使用C#实现简单Scoket连接及服务端与客户端通讯
简介: 网络编程是个很有意思的事情,偶然翻出来很久之前刚开始看Socket的时候写的一个实例,贴出来吧 Unity中实现简单的Socket连接,c#中提供了丰富的API,直接上代码. 服务端代码: [ ...
- 【spoj NSUBSTR】 Substrings
http://www.spoj.com/problems/NSUBSTR/ (题目链接) 题意 给出一个字符串S,令${F(x)}$表示S的所有长度为x的子串出现次数的最大值.求${F(1)..... ...
- 解题:JXOI 2018 游戏
题面 From ZRQ,很好的计数题 我们可以发现这$len=r-l+1$个数中有一些是必须被查到的,即它们不是一些数的倍数,它们的数目$imp$可以通过一次埃氏筛求出. 在一个排列中可怜查到某个位置 ...
- 旧题新做:从idy的视角看数据结构
“今天你不写总结……!!!” 额…… 还是讲我的吧.这些考试都是idy出的题. 20170121:DFS序. ST表.线段树练习 这是第一次考数据结构. Problem 1. setsum 1 sec ...