Skip to content

Commit

Permalink
bfe_wasm
Browse files Browse the repository at this point in the history
Signed-off-by: xuleiming <xuleiming@yf-networks.com>
  • Loading branch information
xuleiming committed Dec 3, 2024
1 parent 9f0a6be commit d1f3a8f
Show file tree
Hide file tree
Showing 41 changed files with 2,562 additions and 51 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ strip: prepare compile-strip package
# make prepare, download dependencies
prepare: prepare-dep prepare-gen
prepare-dep:
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc)
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc@latest)
prepare-gen:
cd "bfe_basic/condition/parser" && $(GOGEN)

Expand Down Expand Up @@ -117,7 +117,7 @@ package:
# make deps
deps:
$(call PIP_INSTALL_PKG, pre-commit)
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc)
$(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc@latest)
$(call INSTALL_PKG, staticcheck, honnef.co/go/tools/cmd/staticcheck)
$(call INSTALL_PKG, license-eye, github.com/apache/skywalking-eyes/cmd/license-eye@latest)

Expand Down
5 changes: 5 additions & 0 deletions bfe_config/bfe_conf/conf_basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ type ConfigBasic struct {
DebugBfeRoute bool // whether open bferoute debug log
DebugBal bool // whether open bal debug log
DebugHealthCheck bool // whether open health check debug log

// wasm plugin path
BfeWasmPath string //root path of wasm plugins
}

func (cfg *ConfigBasic) SetDefaultConf() {
Expand Down Expand Up @@ -99,6 +102,8 @@ func (cfg *ConfigBasic) SetDefaultConf() {
cfg.NameConf = "server_data_conf/name_conf.data"

cfg.MonitorInterval = 20

cfg.BfeWasmPath = "plugin"
}

func (cfg *ConfigBasic) Check(confRoot string) error {
Expand Down
4 changes: 4 additions & 0 deletions bfe_modules/bfe_modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/bfenetworks/bfe/bfe_modules/mod_trust_clientip"
"github.com/bfenetworks/bfe/bfe_modules/mod_userid"
"github.com/bfenetworks/bfe/bfe_modules/mod_waf"
"github.com/bfenetworks/bfe/bfe_modules/mod_wasmplug"
)

// list of all modules, the order is very important
Expand Down Expand Up @@ -131,6 +132,9 @@ var moduleList = []bfe_module.BfeModule{

// mod_access
mod_access.NewModuleAccess(),

// mod_wasm
mod_wasmplug.NewModuleWasm(),
}

// init modules list
Expand Down
278 changes: 278 additions & 0 deletions bfe_modules/mod_wasmplug/conf_mod_wasmplug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
package mod_wasmplug

import (
"fmt"
"os"
"path"
"sync"

"github.com/baidu/go-lib/log"
"github.com/bfenetworks/bfe/bfe_basic/condition"
"github.com/bfenetworks/bfe/bfe_util"
"github.com/bfenetworks/bfe/bfe_util/json"
"github.com/bfenetworks/bfe/bfe_wasmplug"
gcfg "gopkg.in/gcfg.v1"
)

type ConfModWasm struct {
Basic struct {
WasmPluginPath string // path of Wasm plugins
DataPath string // path of config data
}

Log struct {
OpenDebug bool
}
}

// ConfLoad loads config from config file
func ConfLoad(filePath string, confRoot string) (*ConfModWasm, error) {
var cfg ConfModWasm
var err error

// read config from file
err = gcfg.ReadFileInto(&cfg, filePath)
if err != nil {
return &cfg, err
}

// check conf of mod_redirect
err = cfg.Check(confRoot)
if err != nil {
return &cfg, err
}

return &cfg, nil
}

func (cfg *ConfModWasm) Check(confRoot string) error {
if cfg.Basic.WasmPluginPath == "" {
log.Logger.Warn("ModWasm.WasmPluginPath not set, use default value")
cfg.Basic.WasmPluginPath = "mod_wasm"
}
cfg.Basic.WasmPluginPath = bfe_util.ConfPathProc(cfg.Basic.WasmPluginPath, confRoot)

if cfg.Basic.DataPath == "" {
log.Logger.Warn("ModWasm.DataPath not set, use default value")
cfg.Basic.WasmPluginPath = "mod_wasm/wasm.data"
}
cfg.Basic.DataPath = bfe_util.ConfPathProc(cfg.Basic.DataPath, confRoot)

return nil
}

type PluginConfFile struct {
Version *string // version of the config
BeforeLocationRules *[]FilterRuleFile // rule list for BeforeLocation
ProductRules *map[string][]FilterRuleFile // product --> rule list
PluginMap *map[string]PluginMeta
}

type FilterRuleFile struct {
Cond *string // condition for plugin
PluginList *[]string
}

type PluginMeta struct {
Name string
WasmVersion string
ConfVersion string
// Md5 string
InstanceNum int
Product string
}

type FilterRule struct {
Cond condition.Condition // condition for plugin
PluginList []*bfe_wasmplug.WasmPlugin
}

type RuleList []FilterRule
type ProductRules map[string]*RuleList // product => list of filter rules

func updatePluginConf(t *PluginTable, conf PluginConfFile, pluginPath string) error {
if conf.Version != nil && *conf.Version != t.GetVersion() {
pluginMapNew := make(map[string]*bfe_wasmplug.WasmPlugin)
var beforeLocationRulesNew RuleList
productRulesNew := make(ProductRules)

// 1. check plugin map
unchanged := make(map[string]bool)

pm := t.GetPluginMap()
if conf.PluginMap != nil {
for pn, p := range *conf.PluginMap {
plugOld := (*pm)[pn]
// check whether plugin version changed.
if plugOld != nil {
configOld := (*plugOld).GetConfig()
if configOld.WasmVersion == p.WasmVersion && configOld.ConfigVersion == p.ConfVersion {
// not change, just copy to new map
pluginMapNew[pn] = plugOld

// ensure instance num
actual := (*plugOld).EnsureInstanceNum(p.InstanceNum)
if actual != p.InstanceNum {
// log.DefaultLogger.Errorf("[wasm][plugin] NewWasmPlugin fail to ensure instance num, want: %v got 0", instanceNum)
return fmt.Errorf("can not EnsureInstanceNum, plugin:%s, num:%d", pn, p.InstanceNum)
}

unchanged[pn] = true
continue
}
}
// if changed, construct a new plugin.
wasmconf := bfe_wasmplug.WasmPluginConfig {
PluginName: pn,
WasmVersion: p.WasmVersion,
ConfigVersion: p.ConfVersion,
InstanceNum: p.InstanceNum,
Path: path.Join(pluginPath, pn),
// Md5: p.Md5,
}
plug, err := bfe_wasmplug.NewWasmPlugin(wasmconf)
if err != nil {
// build plugin error
return err
}

plug.OnPluginStart()

pluginMapNew[pn] = &plug
}
}

// 2. construct product rules
if conf.BeforeLocationRules != nil {
for _, r := range *conf.BeforeLocationRules {
rule := FilterRule{}
cond, err := condition.Build(*r.Cond)
if err != nil {
return err
}
rule.Cond =cond
for _, pn := range *r.PluginList {
plug := pluginMapNew[pn]
if plug == nil {
return fmt.Errorf("unknown plugin: %s", pn)
}
rule.PluginList = append(rule.PluginList, plug)
}
beforeLocationRulesNew = append(beforeLocationRulesNew, rule)
}
}

if conf.ProductRules != nil {
for product, rules := range *conf.ProductRules {
var rulelist RuleList
for _, r := range rules {
rule := FilterRule{}
cond, err := condition.Build(*r.Cond)
if err != nil {
return err
}
rule.Cond =cond
for _, pn := range *r.PluginList {
plug := pluginMapNew[pn]
if plug == nil {
return fmt.Errorf("unknown plugin: %s", pn)
}
rule.PluginList = append(rule.PluginList, plug)
}
rulelist = append(rulelist, rule)
}
productRulesNew[product] = &rulelist
}
}

// 3. update PluginTable
t.Update(*conf.Version, &beforeLocationRulesNew, productRulesNew, &pluginMapNew)

// 4. stop & clear old plugins
for pn, plug := range *pm {
if _, ok := unchanged[pn]; !ok {
// stop plug
(*plug).OnPluginDestroy()
(*plug).Clear()
}
}
}
return nil
}

type PluginTable struct {
lock sync.RWMutex
version string
beforeLocationRules *RuleList
productRules ProductRules
pluginMap *map[string]*bfe_wasmplug.WasmPlugin
}

func NewPluginTable() *PluginTable {
t := new(PluginTable)
t.productRules = make(ProductRules)
t.pluginMap = new(map[string]*bfe_wasmplug.WasmPlugin)
return t
}

func (t *PluginTable) Update(version string, beforeLocationRules *RuleList, productRules ProductRules, pluginMap *map[string]*bfe_wasmplug.WasmPlugin) {
t.lock.Lock()

t.version = version
t.beforeLocationRules = beforeLocationRules
t.productRules = productRules
t.pluginMap = pluginMap

t.lock.Unlock()
}

func (t *PluginTable) GetVersion() string {
defer t.lock.RUnlock()
t.lock.RLock()
return t.version
}

func (t *PluginTable) GetPluginMap() *map[string]*bfe_wasmplug.WasmPlugin {
defer t.lock.RUnlock()
t.lock.RLock()
return t.pluginMap
}

func (t *PluginTable) GetBeforeLocationRules() *RuleList {
defer t.lock.RUnlock()
t.lock.RLock()
return t.beforeLocationRules
}

func (t *PluginTable) Search(product string) (*RuleList, bool) {
t.lock.RLock()
productRules := t.productRules
t.lock.RUnlock()

rules, ok := productRules[product]
return rules, ok
}


func pluginConfLoad(filename string) (PluginConfFile, error) {
var conf PluginConfFile

/* open the file */
file, err := os.Open(filename)

if err != nil {
return conf, err
}

/* decode the file */
decoder := json.NewDecoder(file)

err = decoder.Decode(&conf)
file.Close()

if err != nil {
return conf, err
}

return conf, nil
}
Loading

0 comments on commit d1f3a8f

Please sign in to comment.