diff --git a/cmd/config/config.go b/cmd/config/config.go index f6a4d783..2f7c2d80 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -3,6 +3,7 @@ package config import ( "log" + "github.com/fsnotify/fsnotify" "github.com/go-playground/validator/v10" "github.com/spf13/pflag" "github.com/spf13/viper" @@ -88,6 +89,7 @@ func init() { if err := v.ReadInConfig(); err != nil { log.Printf("Unable to read config file, %v", err) + isConfigFileAvailable = false } log.Printf("Get raw config: %+v", v.AllSettings()) @@ -101,3 +103,12 @@ func (c *UpfConfig) Validate() error { func (c *UpfConfig) Unmarshal() error { return v.UnmarshalExact(c) } + +var isConfigFileAvailable bool = true + +func WatchConfig(onConfigChange func(e fsnotify.Event)) { + if isConfigFileAvailable { + viper.OnConfigChange(onConfigChange) + viper.WatchConfig() + } +} diff --git a/cmd/config/startup.go b/cmd/config/startup.go index e677fd89..4acf8bc8 100644 --- a/cmd/config/startup.go +++ b/cmd/config/startup.go @@ -18,3 +18,19 @@ func Init() { log.Printf("Apply eUPF config: %+v", Conf) } + +func ReadConfig() (UpfConfig, error) { + var conf UpfConfig + if err := conf.Unmarshal(); err != nil { + log.Fatalf("Unable to decode into struct, %v", err) + return UpfConfig{}, err + } + + if err := conf.Validate(); err != nil { + log.Fatalf("eUPF config is invalid: %v", err) + return UpfConfig{}, err + } + + log.Printf("Read config: %+v", conf) + return conf, nil +} diff --git a/cmd/core/api.go b/cmd/core/api.go index 7db6745d..b98a40cf 100644 --- a/cmd/core/api.go +++ b/cmd/core/api.go @@ -36,18 +36,18 @@ func CreateApiServer(bpfObjects *ebpf.BpfObjects, pfcpSrv *PfcpConnection, forwa v1.GET("upf_pipeline", ListUpfPipeline(bpfObjects)) v1.GET("xdp_stats", DisplayXdpStatistics(forwardPlaneStats)) v1.GET("packet_stats", DisplayPacketStats(forwardPlaneStats)) - - config := v1.Group("config") + + config := v1.Group("config") { config.GET("", DisplayConfig()) - config.POST("", EditConfig) + config.POST("", UpdateConfig) } - - pdrMap := v1.Group("uplink_pdr_map") + + pdrMap := v1.Group("uplink_pdr_map") { pdrMap.GET(":id", GetUplinkPdrValue(bpfObjects)) pdrMap.PUT(":id", SetUplinkPdrValue(bpfObjects)) - } + } qerMap := v1.Group("qer_map") { @@ -79,7 +79,7 @@ func CreateApiServer(bpfObjects *ebpf.BpfObjects, pfcpSrv *PfcpConnection, forwa return &ApiServer{router: router} } -func EditConfig(c *gin.Context) { +func UpdateConfig(c *gin.Context) { var conf config.UpfConfig if err := c.BindJSON(&conf); err != nil { c.IndentedJSON(http.StatusBadRequest, gin.H{ @@ -90,7 +90,7 @@ func EditConfig(c *gin.Context) { } if err := SetConfig(conf); err != nil { c.IndentedJSON(http.StatusBadRequest, gin.H{ - "message": fmt.Sprintf("Error during editing config: %s", err.Error()), + "message": fmt.Sprintf("Error during updating config: %s", err.Error()), }) } else { c.Status(http.StatusOK) diff --git a/cmd/main.go b/cmd/main.go index bee52dd2..064921e7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,6 +9,7 @@ import ( "github.com/edgecomllc/eupf/cmd/core" "github.com/edgecomllc/eupf/cmd/ebpf" + "github.com/fsnotify/fsnotify" "github.com/cilium/ebpf/link" "github.com/edgecomllc/eupf/cmd/config" @@ -107,6 +108,9 @@ func main() { } }() + // Handle config file change. + config.WatchConfig(OnConfigFileChange) + // Print the contents of the BPF hash map (source IP address -> packet count). ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() @@ -139,3 +143,13 @@ func StringToXDPAttachMode(Mode string) link.XDPAttachFlags { return link.XDPGenericMode } } + +func OnConfigFileChange(e fsnotify.Event) { + if e.Has(fsnotify.Create) || e.Has(fsnotify.Write) { + if conf, err := config.ReadConfig(); err == nil { + if err := core.SetConfig(conf); err != nil { + log.Error().Msgf("Error during config file change handling: %s", err.Error()) + } + } + } +}