主入口

ConfigurableOpenFlowProviderModule是OpenFlowPlugin中启动加载的入口,如下:

@Override
public java.lang.AutoCloseable createInstance() {
pluginProvider = new OpenflowPluginProvider();
pluginProvider.setDataBroker(getDataBrokerDependency());
pluginProvider.setNotificationService(getNotificationServiceDependency());
pluginProvider.setRpcRegistry(getRpcRegistryDependency());
pluginProvider.setSwitchConnectionProviders(getOpenflowSwitchConnectionProviderDependency());
pluginProvider.setRole(getRole()); // 此时获得的role为缺省值NOCHANGE,该值位于AbstractConfigurableOpenFlowProviderModule中
pluginProvider.initialization();
return pluginProvider;
}

其中创建了一个OpenflowPluginProvider,即OpenflowPlugin功能实际提供者,其中调用的initialization方法将服务进行了初始化,如下:

public void initialization() {
messageCountProvider = new MessageSpyCounterImpl();
extensionConverterManager = new ExtensionConverterManagerImpl();
roleManager = new OFRoleManager(OFSessionUtil.getSessionManager()); LOG.debug("dependencies gathered..");
registrationManager = new SalRegistrationManager();
registrationManager.setDataService(dataBroker);
registrationManager.setPublishService(notificationService);
registrationManager.setRpcProviderRegistry(rpcRegistry);
registrationManager.init(); mdController = new MDController();
mdController.setSwitchConnectionProviders(switchConnectionProviders);
mdController.setMessageSpyCounter(messageCountProvider);
mdController.setExtensionConverterProvider(extensionConverterManager);
mdController.init();
mdController.start();
}

下行通道

其中可大体分成两部分,一部分是SalRegistrationManager,另一部分则是MDController。

SalRegistrationManager可以理解为管理了控制器到交换机的下行通道。

在SalRegistrationManager中init方法,注册了SessionListener,当控制器与交换机连接会话发生变化时,会触发onSessionAdded和onSessionRemoved方法,如下:

@Override
public void onSessionAdded(final SwitchSessionKeyOF sessionKey, final SessionContext context) {
GetFeaturesOutput features = context.getFeatures(); // 获取OFPT_FEATURES_REPLY
BigInteger datapathId = features.getDatapathId(); // 从OFPT_FEATURES_REPLY中获取dpid
InstanceIdentifier<Node> identifier = identifierFromDatapathId(datapathId);
NodeRef nodeRef = new NodeRef(identifier);
NodeId nodeId = nodeIdFromDatapathId(datapathId);
ModelDrivenSwitchImpl ofSwitch = new ModelDrivenSwitchImpl(nodeId, identifier, context); // 创建交换机实例
CompositeObjectRegistration<ModelDrivenSwitch> registration =
ofSwitch.register(rpcProviderRegistry); // 注册rpc调用
context.setProviderRegistration(registration); LOG.debug("ModelDrivenSwitch for {} registered to MD-SAL.", datapathId); NotificationQueueWrapper wrappedNotification = new NotificationQueueWrapper(
nodeAdded(ofSwitch, features, nodeRef),
context.getFeatures().getVersion());
context.getNotificationEnqueuer().enqueueNotification(wrappedNotification);
}

可以认为每一台交换机与控制器建立连接后,控制器都会为其创建一个ModelDrivenSwitchImpl实例,并为其注册相应的rpc,而ModelDrivenSwitchImpl则实现了多个rpc接口,继承如下:

public interface ModelDrivenSwitch
extends
SalGroupService,
SalFlowService,
SalMeterService, SalTableService, SalPortService, PacketProcessingService, NodeConfigService,
OpendaylightGroupStatisticsService, OpendaylightMeterStatisticsService, OpendaylightFlowStatisticsService,
OpendaylightPortStatisticsService, OpendaylightFlowTableStatisticsService, OpendaylightQueueStatisticsService,
Identifiable<InstanceIdentifier<Node>>

而AbstractModelDrivenSwitch则实现ModelDrivenSwitch,如下:

public abstract class AbstractModelDrivenSwitch implements ModelDrivenSwitch

在AbstractModelDrivenSwitch中,注册了所有的rpc实现为AbstractModelDrivenSwitch,由于此类为抽象类,因此具体方法的实现将由实现类完成,即ModelDrivenSwitchImpl,如下:

 @Override
public CompositeObjectRegistration<ModelDrivenSwitch> register(RpcProviderRegistry rpcProviderRegistry) {
CompositeObjectRegistrationBuilder<ModelDrivenSwitch> builder = CompositeObjectRegistration
.<ModelDrivenSwitch> builderFor(this); final RoutedRpcRegistration<SalFlowService> flowRegistration = rpcProviderRegistry.addRoutedRpcImplementation(SalFlowService.class, this);
flowRegistration.registerPath(NodeContext.class, getIdentifier()); // 将rpc路由表中的数据进行更新,getIdentifier() 方法带入更新节点的path
builder.add(flowRegistration); ...
}

上述rpc接口的实现均在ModelDrivenSwitchImpl中,以SalFlowService为例,如下:

@Override
public Future<RpcResult<AddFlowOutput>> addFlow(final AddFlowInput input) {
LOG.debug("Calling the FlowMod RPC method on MessageDispatchService");
// use primary connection
SwitchConnectionDistinguisher cookie = null; OFRpcTask<AddFlowInput, RpcResult<UpdateFlowOutput>> task =
OFRpcTaskFactory.createAddFlowTask(rpcTaskContext, input, cookie);
ListenableFuture<RpcResult<UpdateFlowOutput>> result = task.submit(); return Futures.transform(result, OFRpcFutureResultTransformFactory.createForAddFlowOutput());
}

上行通道

MDController负责控制器与交换机的信令交互,即非流表、组表消息的交互,可以理解为控制器与交换机的上行通道管理。在init方法中,交换机与控制器消息处理实现被添加到映射中,如下:

OpenflowPortsUtil.init(); // 完成协议中端口定义的映射
...
// 每个translator对应了Openflow协议中一种消息,负责将Of消息转换为MD-SAL中的各个notification
addMessageTranslator(ErrorMessage.class, OF10, new ErrorV10Translator());
addMessageTranslator(ErrorMessage.class, OF13, new ErrorTranslator());
addMessageTranslator(FlowRemovedMessage.class, OF10, new FlowRemovedTranslator());
addMessageTranslator(FlowRemovedMessage.class, OF13, new FlowRemovedTranslator());
...
// 制定了每种notification的通用pulisher
addMessagePopListener(NodeErrorNotification.class, notificationPopListener);
addMessagePopListener(BadActionErrorNotification.class, notificationPopListener);
addMessagePopListener(BadInstructionErrorNotification.class, notificationPopListener);
addMessagePopListener(BadMatchErrorNotification.class, notificationPopListener);

在init后,调用start方法创建SwitchConnectionHandlerImpl负责与处理交换机连接,start方法会启动一系列SwitchConnectionHandler,这些SwitchConnectionHandler会依次处理连接,以找到一个合适的,如下:

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

角色管理

除去SalRegistrationManager与MDController,OpenflowPluginProvider还创建了一个OFRoleManager实例,在OpenflowPluginProvider中与Role相关的方法如下:

/**
* @param role of instance
*/
public void setRole(OfpRole role) {
this.role = role;
} /**
* @param newRole
*/
public void fireRoleChange(OfpRole newRole) {
if (!role.equals(newRole)) {
LOG.debug("my role was chaged from {} to {}", role, newRole);
role = newRole;
switch (role) {
case BECOMEMASTER:
//TODO: implement appropriate action
roleManager.manageRoleChange(role);
break;
case BECOMESLAVE:
//TODO: implement appropriate action
roleManager.manageRoleChange(role);
break;
case NOCHANGE:
//TODO: implement appropriate action
roleManager.manageRoleChange(role);
break;
default:
LOG.warn("role not supported: {}", role);
break;
}
}
}

从方法实现的角度看,似乎role在OpenflowPluginProvider中是一个集中控制的对象,并非与交换机节点绑定,即对于一定区域内的所有交换机而言,只能出现一个一个master,而不能出现某个交换机在某个控制器上为master的情况。从OFRoleManager提供的方法看似乎也验证了这一点,如下:

/**
* @param sessionManager
*/
public OFRoleManager(final SessionManager sessionManager) {
Preconditions.checkNotNull("Session manager can not be empty.", sessionManager);
this.sessionManager = sessionManager;
workQueue = new PriorityBlockingQueue<>(500, new Comparator<RolePushTask>() { // 队列容量为500
@Override
public int compare(final RolePushTask o1, final RolePushTask o2) {
return Integer.compare(o1.getPriority(), o2.getPriority()); // 按优先级排列的队列
}
});
ThreadPoolLoggingExecutor delegate = new ThreadPoolLoggingExecutor(
1, 1, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), "ofRoleBroadcast");
broadcastPool = MoreExecutors.listeningDecorator(
delegate);
} /**
* change role on each connected device
*
* @param role
*/
public void manageRoleChange(final OfpRole role) {
for (final SessionContext session : sessionManager.getAllSessions()) { // 遍历所有的连接会话
try {
workQueue.put(new RolePushTask(role, session));
} catch (InterruptedException e) {
LOG.warn("Processing of role request failed while enqueueing role task: {}", e.getMessage());
}
} while (!workQueue.isEmpty()) {
RolePushTask task = workQueue.poll();
ListenableFuture<Boolean> rolePushResult = broadcastPool.submit(task); // 该方法会调用RolePushTask中的call方法
CheckedFuture<Boolean, RolePushException> rolePushResultChecked =
RoleUtil.makeCheckedRuleRequestFxResult(rolePushResult);
try {
Boolean succeeded = rolePushResultChecked.checkedGet(TIMEOUT, TIMEOUT_UNIT);
if (!MoreObjects.firstNonNull(succeeded, Boolean.FALSE)) {
if (task.getRetryCounter() < RETRY_LIMIT) {
workQueue.offer(task); // 修改失败role且失败次数小于重试次数的会话重新存入queue
}
}
} catch (RolePushException | TimeoutException e) {
LOG.warn("failed to process role request: {}", e);
}
}
}

RolePushTask中的call方法将发送RoleRequest,如下:

generationId = RoleUtil.getNextGenerationId(generationId);

// try to possess role on device
Future<RpcResult<RoleRequestOutput>> roleReply = RoleUtil.sendRoleChangeRequest(session, role, generationId);
// flush election result with barrier
BarrierInput barrierInput = MessageFactory.createBarrier(
session.getFeatures().getVersion(), session.getNextXid());
Future<RpcResult<BarrierOutput>> barrierResult = session.getPrimaryConductor().getConnectionAdapter().barrier(barrierInput);

改变Role的顶层调用在OpenflowPluginProvider的fireRoleChange方法中,如下,该方法只在ConfigurableOpenFlowProviderModule中reuseInstance被调用

public void fireRoleChange(OfpRole newRole) {
if (!role.equals(newRole)) {
LOG.debug("my role was chaged from {} to {}", role, newRole);
role = newRole;
switch (role) {
case BECOMEMASTER:
//TODO: implement appropriate action
roleManager.manageRoleChange(role);
break;
case BECOMESLAVE:
//TODO: implement appropriate action
roleManager.manageRoleChange(role);
break;
case NOCHANGE:
//TODO: implement appropriate action
roleManager.manageRoleChange(role);
break;
default:
LOG.warn("role not supported: {}", role);
break;
}
}
}

从代码看目前对于角色转换的功能是需要开发者加入的,并从外部调用实现交换机角色的切换,且更倾向于主备的实现方式。

Openflow消息转译

MDController中注册了各种Openflow协议消息的处理器,这些处理器均继承自IMDMessageTranslator<I, O>,这是一个翻译器,所有到MD-SAL或往MD-SAL的消息都由它处理,它只有一个方法,如下:

/**
* This method is called in order to translate message to MD-SAL or from MD-SAL.
*
* @param cookie
* auxiliary connection identifier
* @param sc
* The SessionContext which sent the OF message
* @param msg
* The OF message
*
* @return translated message
*/
O translate(SwitchConnectionDistinguisher cookie, SessionContext sc, I msg);

其中cookie一般不会被使用,translate方法可以参照以下步骤实现:

@Override
public List<DataObject> translate(SwitchConnectionDistinguisher cookie,
SessionContext sc, OfHeader msg) {
if(msg instanceof OF_MESSAGE.class) { // 判断消息是否属于要处理的消息类型
// 按消息格式填充各个字段
...
return list;
} else {
return Collections.emptyList(); // 处理出错则返回一个空的列表
}
}

MDController

方法start创建了SwitchConnectionHandlerImpl对象,此处似乎与上图不符,如下:

public void start() {
LOG.debug("starting ..");
LOG.debug("switchConnectionProvider: " + switchConnectionProviders);
// setup handler
SwitchConnectionHandlerImpl switchConnectionHandler = new SwitchConnectionHandlerImpl(); // 实际创建了一个queuekeeper
switchConnectionHandler.setMessageSpy(messageSpyCounter); errorHandler = new ErrorHandlerSimpleImpl(); // 为捕获异常创建实例 switchConnectionHandler.setErrorHandler(errorHandler);
switchConnectionHandler.init(); // 经过调用,真正地注册了translator和popListener 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);
}

Openflow Plugin学习笔记1的更多相关文章

  1. Openflow Plugin学习笔记3

    MDController.java 中的start方法,创建了SwitchConnectionHandlerImpl实例 SwitchConnectionHandlerImpl switchConne ...

  2. Openflow Plugin学习笔记2

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

  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. bl bl bl bl bl

    package com.dh.activiti; import org.springframework.web.servlet.HandlerInterceptor; import org.sprin ...

  2. paoding rose controller包及文件名命名规则

    1.包命名规则:xxx.xxx.controllers(否则扫描不到)

  3. sleep() 与 wait()的比较

    1.这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类. sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还 ...

  4. 超链接提示效果jQuery+CSS+html

    我们知道浏览器自带了超链接提示, 只需要在超链接中加入 title 属性就可以了. <a href="#" title="吉大砍人案致1死1伤 受害者死前大喊他手里 ...

  5. 【刷题】BZOJ 4196 [Noi2015]软件包管理器

    Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖( ...

  6. [APIO2014]回文串 manacher 后缀数组

    题面:洛谷 题解: 还是这个性质:对于每个串而言,本质不同的回文串最多只有O(n)个. 所以我们先求出这O(n)个本质不同的回文串,然后对整个串求一次sa. 然后对于每个回文串,求出它的出现次数,更新 ...

  7. 【BZOJ5306】[HAOI2018]染色(NTT)

    [BZOJ5306]染色(NTT) 题面 BZOJ 洛谷 题解 我们只需要考虑每一个\(W[i]\)的贡献就好了 令\(lim=min(M,\frac{N}{S})\) 那么,开始考虑每一个\(W[i ...

  8. Unity3D手游开发日记(5) - 适合移动平台的植被随风摆动

    一直在思考怎么让场景更有生机,我觉得植被的随风摆动是必不可少的.CE3引擎的植被bending就做得特别棒.我也准备在手机上做一套. 先分析一下植被摆动常见的几种做法.其实不管哪种做法,核心就是让植被 ...

  9. python基础(4)

    条件判断和循环 条件判断 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断. 比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,用if语句实现: age = 20 if ag ...

  10. 【bzoj4559】成绩比较

    Portal -->bzoj4559 补档计划 ​  借这题补个档--拉格朗日插值 ​​  插值的话大概就是有一个\(n-1\)次多项式\(A(x)\),你只知道它在\(n\)处的点值,分别是\ ...