Floodlight 源碼解讀 :Main

Floodlight 的 Main 解析圖


須要理解的概念

模塊(Module)

Module 是指繼承了 IFloodlightModule 接口的類服務器

IFloodlightModule的相關注釋ide

Defines an interface for loadable Floodlight modules.
 At a high level, these functions are called in the following order:
 
  getModuleServices() : 得到模塊實現的服務列表
  getServiceImpls(); 實例化並返回:服務實現類-實現此服務的對象 映射
  getModuleDependencies() : 得到模塊依賴的列表
  init() : internal initializations (<em>don't</em> touch other modules)
  startUp() : external initializations (<em>do</em> touch other modules)

全部可加載的模塊都有這幾種方法,在接下來的加載模塊時須要使用到。
每一個具體的模塊都會重寫這幾個函數,下面舉個 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 的服務 IFloodlightProviderServiceoop

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;
}

返回服務實現類和實現用的對象的Map。spa

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(),到對應的模塊去看就能夠了。
有的模塊是沒有服務依賴的,好比 ThreadPool模塊。debug

服務(Service)

Service 是指繼承了 IFloodlightService 接口的類。code

public abstract interface IFloodlightService {
   // This space is intentionally left blank....don't touch it
}

模塊使用getModuleServices()方法能夠得到對應的服務列表,能夠到源碼去看對應的服務功能。對象

Main函數

  1. 解析命令行參數
  2. 加載模塊
  3. 啓動 REST 服務器
  4. 啓動 Controller

命令行參數解析

CmdLineSetting 定義了命令行參數的格式繼承

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指定配置文件路徑,則使用默認路徑「src/main/resources/floodlightdefault.properties」

CmdLineParser 解析命令參數

CmdLineParser parser = new CmdLineParser(settings)
parser.parserArgument(args)

加載模塊

moduleContext=fml.loadModulesFromConfig(settings.getModuleFile())
settings.getModuleFile()提供配置文件的路徑

mergeProperties()

  • 目的是得到配置文件裏的模塊的集合configMods和prop是除去配置文件裏的模塊鍵值對後剩餘的配置信息(模塊的配置參數)

loadModulesFromList(configsMods,prop)

findAllModule(configMods)
  • 填充moduleNameMap,moduleServiceMap,ServiceMap

這個方法比較重要的是這個 ServiceLoader,返回服務加載器

ServiceLoader<IFloodlightModule> moduleLoader =
            ServiceLoader.load(IFloodlightModule.class, cl);

ServiceLoader 爲了註冊服務,須要在類路徑 src/main/resources/META_INF/services文件夾內列好註冊服務的模塊,能夠獲得繼承了 IFloodlightModule 接口的實現類
使用moduleLoader.iterator()迭代器去填充moduleNameMap,moduleServiceMap,ServiceMap
moduleNameMap 模塊名稱-模塊對象 Map
moduleServiceMAP 模塊名稱-模塊服務 Map
ServiceMap 模塊服務-模塊名稱 Map

traverseDeps(moduleName,modsToLoad,moduleList,moduleMap,modsVisited)
addModule()
  • 添加模塊到模塊的哈希集moduleMap,同時註冊它們的服務(即獲得已加載模塊序列 moduleList)
parseConfigParameters(prop)
  • 解析每一個模塊的配置參數

取配置文件的一條參數配置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);
        }

若是系統屬性已經存在,則使用系統屬性的值,若是不存在,則configValue = prop.getProperty(key);【即 configValue 在此處爲in-port, vlan, mac, ip, transport】

floodlightModuleContext.addConfigParam(mod,configKey,configValue)
  • 添加模塊的配置參數

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)
  • 初始化已加載模塊列表下的模塊

得到模塊的服務實例

Map<Class<? extends IFloodlightService>,
            IFloodlightService> simpls = module.getServiceImpls();

添加服務到 floodlightModuleContext

if (floodlightModuleContext.getServiceImpl(s.getKey()) == null) {
                    floodlightModuleContext.addService(s.getKey(),
                                                       s.getValue());

遍歷已加載模塊集,開始初始化模塊,調用模塊的方法:init

for (IFloodlightModule module : moduleSet) {
        // init the module
        if (logger.isDebugEnabled()) {
            logger.debug("Initializing " +
                         module.getClass().getCanonicalName());
        }
        module.init(floodlightModuleContext);
    }
startupModules(moduleList)
  • 調用已加載模塊的啓動方法

遍歷已加載模塊集,調用每一個模塊的啓動方法

for (IFloodlightModule m : moduleSet) {
        if (logger.isDebugEnabled()) {
            logger.debug("Starting " + m.getClass().getCanonicalName());
        }
        m.startUp(floodlightModuleContext);
    }
return floodlightModuleContext

返回公共環境變量

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 循環遍歷模塊中的方法,找到@run註解的方法爲主方法,如下的就是 FloodlightProvider 提供的 run 方法

@Run(mainLoop=true)
public void run() throws FloodlightModuleException {
    controller.run();
}

運行控制器的模塊

mainLoopMethods.get(0).run();
相關文章
相關標籤/搜索