Floodlight 的 Main 解析圖
需要理解的概念
模塊(Module)
Module 是指繼承了 IFloodlightModule 接口的類
IFloodlightModule的相關(guān)注釋
Defines an interface for loadable Floodlight modules.
At a high level, these functions are called in the following order:
getModuleServices() : 獲得模塊實現(xiàn)的服務(wù)列表
getServiceImpls(); 實例化并返回:服務(wù)實現(xiàn)類-實現(xiàn)此服務(wù)的對象 映射
getModuleDependencies() : 獲得模塊依賴的列表
init() : internal initializations (<em>don't</em> touch other modules)
startUp() : external initializations (<em>do</em> touch other modules)
所有可加載的模塊都有這幾種方法,在接下來的加載模塊時需要使用到席舍。
每個具體的模塊都會重寫這幾個函數(shù)布轿,下面舉個 FloodlightProvider 的例子。
getModuleServices()
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Collection<Class<? extends IFloodlightService>> services =
new ArrayList<Class<? extends IFloodlightService>>(1);
services.add(IFloodlightProviderService.class);
return services;
}
獲得 FloodlightProvider 的服務(wù) IFloodlightProviderService
getServiceImple()
@Override
public Map<Class<? extends IFloodlightService>,
IFloodlightService> getServiceImpls() {
controller = new Controller();
Map<Class<? extends IFloodlightService>,
IFloodlightService> m =
new HashMap<Class<? extends IFloodlightService>,
IFloodlightService>();
m.put(IFloodlightProviderService.class, controller);
return m;
}
返回服務(wù)實現(xiàn)類和實現(xiàn)用的對象的Map来颤。
getModuleDependencies()
@Override
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Collection<Class<? extends IFloodlightService>> dependencies =
new ArrayList<Class<? extends IFloodlightService>>(4);
dependencies.add(IStorageSourceService.class);
dependencies.add(IPktInProcessingTimeService.class);
dependencies.add(IRestApiService.class);
dependencies.add(IDebugCounterService.class);
dependencies.add(IOFSwitchService.class);
dependencies.add(IThreadPoolService.class);
dependencies.add(ISyncService.class);
return dependencies;
}
返回依賴的列表
其他
init(),startup()汰扭,到對應(yīng)的模塊去看就可以了。
有的模塊是沒有服務(wù)依賴的福铅,比如 ThreadPool模塊萝毛。
服務(wù)(Service)
Service 是指繼承了 IFloodlightService 接口的類。
public abstract interface IFloodlightService {
// This space is intentionally left blank....don't touch it
}
模塊使用getModuleServices()方法可以獲得對應(yīng)的服務(wù)列表滑黔,可以到源碼去看對應(yīng)的服務(wù)功能笆包。
Main函數(shù)
- 解析命令行參數(shù)
- 加載模塊
- 啟動 REST 服務(wù)器
- 啟動 Controller
命令行參數(shù)解析
CmdLineSetting 定義了命令行參數(shù)的格式
public static final String DEFAULT_CONFIG_FILE = "src/main/resources/floodlightdefault.properties";
@Option(name="-cf", aliases="--configFile", metaVar="FILE", usage="Floodlight configuration file")
private String configFile = DEFAULT_CONFIG_FILE;
如果沒有使用-cf指定配置文件路徑环揽,則使用默認(rèn)路徑“src/main/resources/floodlightdefault.properties”
CmdLineParser 解析命令參數(shù)
CmdLineParser parser = new CmdLineParser(settings)
parser.parserArgument(args)
加載模塊
moduleContext=fml.loadModulesFromConfig(settings.getModuleFile())
settings.getModuleFile()提供配置文件的路徑
mergeProperties()
- 目的是獲得配置文件里的模塊的集合configMods和prop是除去配置文件里的模塊鍵值對后剩余的配置信息(模塊的配置參數(shù))
loadModulesFromList(configsMods,prop)
findAllModule(configMods)
- 填充moduleNameMap,moduleServiceMap,ServiceMap
這個方法比較重要的是這個 ServiceLoader,返回服務(wù)加載器
ServiceLoader<IFloodlightModule> moduleLoader =
ServiceLoader.load(IFloodlightModule.class, cl);
ServiceLoader 為了注冊服務(wù)庵佣,需要在類路徑 src/main/resources/META_INF/services文件夾內(nèi)列好注冊服務(wù)的模塊歉胶,可以得到繼承了 IFloodlightModule 接口的實現(xiàn)類
使用moduleLoader.iterator()迭代器去填充moduleNameMap,moduleServiceMap,ServiceMap
moduleNameMap 模塊名稱-模塊對象 Map
moduleServiceMAP 模塊名稱-模塊服務(wù) Map
ServiceMap 模塊服務(wù)-模塊名稱 Map
traverseDeps(moduleName,modsToLoad,moduleList,moduleMap,modsVisited)
addModule()
- 添加模塊到模塊的哈希集moduleMap,同時注冊它們的服務(wù)(即得到已加載模塊序列 moduleList)
parseConfigParameters(prop)
- 解析每個模塊的配置參數(shù)
取配置文件的一條參數(shù)配置net.floodlightcontroller.forwarding.Forwarding.match=in-port, vlan, mac, ip, transport舉例
key:net.floodlightcontroller.forwarding.Forwarding.match
String configKey=key.substring(LastPeriod+1)
獲到的就是 match,即 configKey=match
String systemKey = System.getProperty(key);
if (systemKey != null) {
configValue = systemKey;
} else {
configValue = prop.getProperty(key);
}
如果系統(tǒng)屬性已經(jīng)存在秧了,則使用系統(tǒng)屬性的值跨扮,如果不存在,則configValue = prop.getProperty(key);【即 configValue 在此處為in-port, vlan, mac, ip, transport】
floodlightModuleContext.addConfigParam(mod,configKey,configValue)
- 添加模塊的配置參數(shù)
FloodlightModuleLoader 類下的方法
public void addConfigParam(IFloodlightModule mod, String key, String value) {
Map<String, String> moduleParams = configParams.get(mod.getClass());
if (moduleParams == null) {
moduleParams = new HashMap<String, String>();
configParams.put(mod.getClass(), moduleParams);
}
moduleParams.put(key, value);
}
initModules(moduleList)
- 初始化已加載模塊列表下的模塊
獲得模塊的服務(wù)實例
Map<Class<? extends IFloodlightService>,
IFloodlightService> simpls = module.getServiceImpls();
添加服務(wù)到 floodlightModuleContext
if (floodlightModuleContext.getServiceImpl(s.getKey()) == null) {
floodlightModuleContext.addService(s.getKey(),
s.getValue());
遍歷已加載模塊集验毡,開始初始化模塊衡创,調(diào)用模塊的方法:init
for (IFloodlightModule module : moduleSet) {
// init the module
if (logger.isDebugEnabled()) {
logger.debug("Initializing " +
module.getClass().getCanonicalName());
}
module.init(floodlightModuleContext);
}
startupModules(moduleList)
- 調(diào)用已加載模塊的啟動方法
遍歷已加載模塊集,調(diào)用每個模塊的啟動方法
for (IFloodlightModule m : moduleSet) {
if (logger.isDebugEnabled()) {
logger.debug("Starting " + m.getClass().getCanonicalName());
}
m.startUp(floodlightModuleContext);
}
return floodlightModuleContext
返回公共環(huán)境變量
fml.runModules()
- 運動控制器模塊和所有模塊
getModuleList()
- 獲得一個按初始化順序的模塊列表
返回一個不可修改的已加載模塊序列晶通,如果沒被初始化則返回 null
public List<IFloodlightModule> getModuleList() {
if (loadedModuleList == null)
return Collections.emptyList();
else
return Collections.unmodifiableList(loadedModuleList);
}
runModules()
for (IFloodlightModule m : getModuleList()) {
for (Method method : m.getClass().getDeclaredMethods()) {
Run runAnnotation = method.getAnnotation(Run.class);
if (runAnnotation != null) {
RunMethod runMethod = new RunMethod(m, method);
if(runAnnotation.mainLoop()) {
mainLoopMethods.add(runMethod);
} else {
runMethod.run();
}
}
}
}
for 循環(huán)遍歷模塊中的方法璃氢,找到@run注解的方法為主方法,以下的就是 FloodlightProvider 提供的 run 方法
@Run(mainLoop=true)
public void run() throws FloodlightModuleException {
controller.run();
}
運行控制器的模塊
mainLoopMethods.get(0).run();