Project: BFE (Orchestration & Management / Service Proxy)
File: how_to_write_module.md

When writing a module for BFE, the following aspects should be considered: How to load configuration How to write and register callback functions How to expose internal states mod_block is used as an example for ease of understanding. For a given module, there are 2 types of configuration: Static configuration: be loaded when BFE starts There is only one such configuration file for each module The name of the configuration file is the same as the module name. It is suffixed with .conf Example: mod_block.conf Dynamic configuration: be loaded when BFE starts. It can also be hot-reloaded without restarting BFE. There can be one or more such configuration files for each module The name of the configuration file usually ends with .data Example: blockrules.data and ipblocklist.data in mod_block The configuration files of the modules should be placed in Example: Configuration files of mod_block are located in Configuration files are verified whenever they are loaded, regardless of static or dynamic configuration. BFE fails to start if the configuration files fails to be loaded. BFE will continue to run if dynamic configuration fails to be hot-reloaded. For dynamic configurations, it is required to register callback function on dedicated web server. Hot-reload of dynamic configuration can be triggered by accessing specified URL. Example: In the init function of mod_block, there is some logic as follows, used to register callback function for configuration reload() ```golang // register web handler for reload err = whs.RegisterHandler(web_monitor.WebHandleReload, m.name, m.loadConfData) if err != nil { ... } ``` Write callback functions for appropriate callback point. Note that for different callback points, definition of callback functions may be different. Definition of callback points and callback functions in BFE can be found in . Example: there are two callback functions defined in mod_block() ```golang func (m ModuleBlock) globalBlockHandler(session bfe_basic.Session) int { ... } func (m ModuleBlock) productBlockHandler(request bfebasic.Request) (int, *bfehttp.Response) { ... } ``` Callback functions should be registered when the module is

Example: registration of callback functions in mod_block is as follows() ```golang func (m ModuleBlock) Init(cbs bfemodule.BfeCallbacks, whs *webmonitor.WebHandlers, cr string) error { ... // register handler err = cbs.AddFilter(bfe_module.HandleAccept, m.globalBlockHandler) if err != nil { ... } err = cbs.AddFilter(bfe_module.HandleFoundProduct, m.productBlockHandler) if err != nil { ... } ... } ``` For each BFE module, it is strongly recommended to expose enough internal states. To expose internal states of a module, do the following 3 steps: Define state variables Register callback function for exposing internal states Insert code for doing statistic Firstly, design statistical metrics and define them as member variables. Example: define ModuleBlockState in mod_block () ```golang type ModuleBlockState struct { ConnTotal *metrics.Counter // all connnetion checked ConnAccept *metrics.Counter // connection passed ConnRefuse *metrics.Counter // connection refused ReqTotal *metrics.Counter // all request in ReqAccept *metrics.Counter // request accepted ReqRefuse *metrics.Counter // request refused WrongCommand *metrics.Counter // request with condition satisfied, but wrong command } ``` Secondly, define a member variable of type ModuleBlockState in ModuleBlock. Also define a member variable of type Metrics for related calculations. ```golang type ModuleBlock struct { ... state ModuleBlockState // module state metrics metrics.Metrics ... ``` Thirdly, do initialization in constructor function. ```golang func NewModuleBlock() *ModuleBlock { m := new(ModuleBlock) m.name = ModBlock m.metrics.Init(&m.state, ModBlock, 0) ... } ``` In order to expose internal status, callback function should be implemented. Example: In mod_block, there is logic as follows, where monitorHandlers () is the callback function() ```golang func (m *ModuleBlock) getState(params mapstring) ([]byte, error) { s := m.metrics.GetAll() return s.Format(params) } func (m *ModuleBlock) getStateDiff(params mapstring) ([]byte, error) { s := m.metrics.GetDiff() return s.Format(params) } func (m *ModuleBlock) monitorHandlers() map[string]interface{} { handlers := map[string]interface{}{ m.name: m.getState, m.name + ".diff": m.getStateDiff, } return handlers } ``` Then register callback function during module initialization. ```golang // register web handler for monitor err = webmonitor.RegisterHandlers(whs, webmonitor.WebHandleMonitor, m.monitorHandlers()) if err != nil { ... } ``` Insert some code for doing statistic. Example: ```golang func (m ModuleBlock) globalBlockHandler(session bfe_basic.Session) int { ... m.state.ConnTotal.Inc(1) ... } ```