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的更多相关文章

  1. Openflow Plugin学习笔记2

    OpenDaylight OpenFlow Plugin 过载保护 过载保护 OF Plugin中的过载保护按如下流程工作: ConnectionConductor将消息送入队列,是最靠近OFJava ...

  2. Openflow Plugin学习笔记1

    主入口 ConfigurableOpenFlowProviderModule是OpenFlowPlugin中启动加载的入口,如下: @Override public java.lang.AutoClo ...

  3. OpenFlow Switch学习笔记(五)——Group Table、Meter Table及Counters

    本文主要详述OpenFlow Switch的另外两个主要组件——Group Table和Meter Table,它们在整个OpenFlow Swtich Processing中也起到了重要作用. 1. ...

  4. OpenFlow Switch学习笔记(四)——Matching

    这次我们着重详述来自于网络中的数据包在OpenFlow Switch中与Flow Entries的具体匹配过程,以及当出现Table Miss时的处理方式,下面就将从这两方面说起. 1.Matchin ...

  5. OpenFlow Switch学习笔记(一)——基础概念

    OpenFlow Switch v1.4.0规范是在2013年10月14号发布,规范涵盖了OpenFlow Switch各个组件的功能定义.Controller与Switch之间的通信协议Open F ...

  6. OpenFlow Switch学习笔记(七)——Matching Fields

    Matching Fields in_port=port Matches OpenFlow port port dl_vlan=vlan Matches IEEE 802.1q Virtual LAN ...

  7. OpenFlow Switch学习笔记(六)——Instructions和Actions

    本文主要重点讨论OpenFlow Switch规范的指令集,它们深刻影响着数据包在Switch中的处理行为,下面开始从以下几个部分谈起. 1.Instructions 每一个Flow Entry里都包 ...

  8. OpenFlow Switch学习笔记(三)——Flow Tables

    这次我们主要讨论下OpenFlow Switch的核心组件之一——Flow Tables,以了解其内部的 matching 以及 action handling 机制.下文将会分为几个部分来逐步详述O ...

  9. OpenFlow Switch学习笔记(二)——OpenFlow Ports

    OpenFlow Ports是OpenFlow Switch与剩余网络之间传递Packet的网络接口.OpenFlow Switches之间通过OpenFlow Ports彼此相互逻辑连接.一个Ope ...

随机推荐

  1. Two Sum III - Data structure design

    Design and implement a TwoSum class. It should support the following operations: add and find. add - ...

  2. Ubuntu终端命令--查看端口占用及关闭

    1.查看已连接的服务端口 (ESTABLISHED)     netstat-a 2.查看所有的服务端口(LISTEN,ESTABLISHED)     netstat-ap 3.查看指定端口,可以结 ...

  3. 用join取代not in

    写了好几个页面,速度都上不去,瓶颈在于SQL查询.太多的表,太多的not in,总是从一大推表和数据中筛选出一点数据.看了很多关于SQL优化的文章,都强烈要求不要太多使用not in查询,最好用表连接 ...

  4. BeautifulSoup的find()和findAll()

    BeautifulSoup的提供了两个超级好用的方法(可能是你用bs方法中最常用的).借助这两个函数,你可以通过表现的不同属性轻松过滤HTML(XML)文件,查找需要的标签组或单个标签. 首先find ...

  5. c++11 标准库函数 std::move 和 完美转发 std::forward

    c++11 标准库函数 std::move 和 完美转发 std::forward #define _CRT_SECURE_NO_WARNINGS #include <iostream> ...

  6. 【算法】Tarjan大锦集

    Task1 Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识 ...

  7. 解题:POI 2006 Periods of Words

    题面 洛谷翻译有毒系列 正常人能看懂的题面:若$S$可以通过前缀$s$重复若干次(可重叠)来表示($s!=S$),则称$s$是$S$的一个循环串.求一个字符串所有前缀(包括本身)的最长循环串的长度之和 ...

  8. 【agc003D】Anticube

    Portal --> agc003D Description 给你\(n\)个数,要从里面选出最多的数满足这些选出来的数中任意两个数的乘积都不是立方数 Solution (为什么感觉最近这种解法 ...

  9. 基于Java visualvm的可视化监控的使用

    1 Java visualVM可视化监控工具打开方式 ctrl + r 快捷键调出运行窗口,输出 jvisualvm指令,即可打开java visualVM工具.详情如下图: 2 Java Visua ...

  10. PDF文档小技巧整理一览

    1.福昕阅读器文档背景修改为保护眼睛的颜色? 1)文件 -> 偏好设置 -> 访问 -> 勾选 "改变文档颜色" 2)选择 '自定义颜色'->'页面背景颜色 ...