Multiple updates

- Support to notify about external uci changes
- Call uci_to_dmmap sync function on uci changes notification
- Documentation update
This commit is contained in:
Suvendhu Hansa 2025-09-14 12:10:52 +05:30 committed by IOPSYS Dev
parent 2cd0a1ef6b
commit 786863cf0e
No known key found for this signature in database
7 changed files with 415 additions and 230 deletions

View file

@ -890,6 +890,15 @@ static void perform_uci_sync_op(struct uloop_timeout *timeout)
dynamic_obj[i].uci_sync_handler(); dynamic_obj[i].uci_sync_handler();
} }
} }
struct bbfdm_context *bbfdm_ctx = container_of(timeout, struct bbfdm_context, sync_timer);
if (bbfdm_ctx == NULL)
return;
if (bbfdm_refresh_references(BBFDM_BOTH, bbfdm_ctx->config.out_name)) {
BBF_ERR("Failed to refresh instance data base");
return;
}
} }
static void bbfdm_apply_event_cb(struct ubus_context *ctx __attribute__((unused)), static void bbfdm_apply_event_cb(struct ubus_context *ctx __attribute__((unused)),

View file

@ -6,7 +6,7 @@ List of utilities:
1. bbf.diag 1. bbf.diag
2. bbf.secure 2. bbf.secure
3. bbf.config 3. bbf_configd
## bbf.diag utility ## bbf.diag utility
@ -67,82 +67,349 @@ But storing Secured parameters in plain text in uci/filesystem is bit of a secur
A how to use guide for bbf.secure available [here](https://dev.iopsys.eu/feed/iopsys/-/tree/devel/bbfdm?ref_type=heads#bbf_obfuscation_key) A how to use guide for bbf.secure available [here](https://dev.iopsys.eu/feed/iopsys/-/tree/devel/bbfdm?ref_type=heads#bbf_obfuscation_key)
## bbf.config utility ## bbf_configd
The BBF Config daemon (`bbf_configd`) is a configuration management system designed for device management. It provides UBUS-based configuration commit and revert operations with service monitoring and reload capabilities.
OpenWRT way of reloading services with `ubus call uci commit '{"name":"<uci_name>"}` does not perfectly fits with datamodel requirements. It send a trigger via rpcd to procd by using this ubus call which returns instantly, internally procd reloads for all the services which has a reload dependency configured on that specific uci. OpenWRT way of reloading services with `ubus call uci commit '{"name":"<uci_name>"}` does not perfectly fits with datamodel requirements. It send a trigger via rpcd to procd by using this ubus call which returns instantly, internally procd reloads for all the services which has a reload dependency configured on that specific uci.
Sometimes, there is a good amount of delay in trigger and actual service reload. Sometimes, there is a good amount of delay in trigger and actual service reload.
bbf_configd solves that by adding an in-build reload monitoring functionality which get the list of impacted services and then monitor for PID change for the services with a timeout of 10 sec, with this we make sure Higher layer application(icwmp/obsupa) waits for the application before processing more command.
Bbf.config solves that by adding an in-build reload monitoring functionality which get the list of impacted services and then monitor for PID change for the services with a timeout of 10 sec, with this we make sure Higher layer application(icwmp/obsupa) waits for the application before processing more command. ### Architecture
Currently have two variants of bbf.config, which can be enabled with below compile time configs - **Purpose**: Daemon implementing UBUS interface for configuration management
- **Key Features**:
- Configuration commit/revert operations
- Service monitoring and validation
- Event handling for configuration changes
- Critical service detection and monitoring
1. CONFIG_BBF_CONFIGMNGR_SCRIPT_BACKEND => Simple rpcd script based backend ### UBUS Interface
2. CONFIG_BBF_CONFIGMNGR_C_BACKEND => C based application backend with PID monitoring (default)
### bbf.config Supported methods #### Methods
`bbf.config` provides several methods for managing and monitoring configuration changes in services. These methods can be accessed using the ubus command. ##### `commit`
```bash
$ ubus -v list bbf.config
'bbf.config' @da2cc0d9
"commit":{"services":"Array","proto":"String","reload":"Boolean"} "commit":{"services":"Array","proto":"String","reload":"Boolean"}
- **Description**: Commits configuration changes and reloads affected services
- **Parameters**:
- `services` (array): List of specific services to commit
- `proto` (string): Protocol type ("both", "cwmp", "usp")
- `reload` (bool): Whether to reload services after commit
- **Response**: Status message indicating success or failure
##### `revert`
"revert":{"services":"Array","proto":"String","reload":"Boolean"} "revert":{"services":"Array","proto":"String","reload":"Boolean"}
"changes":{"services":"Array","proto":"String","reload":"Boolean"} - **Description**: Reverts uncommitted configuration changes
- **Parameters**:
- `services` (array): List of specific services to revert
- `proto` (string): Protocol type
- **Response**: Status message indicating success or failure
#### Events
##### `bbfdm.apply`
- **Trigger**: Sent after configuration commits
- **Payload**: Protocol information and list of changed UCI files
- **Purpose**: Notifies components about applied configuration changes to perform synchronization if required
### Configuration Management
#### Protocol Support
The daemon supports multiple protocols with dedicated configuration directories:
| Protocol | Config Directory | DMMAP Directory | Index |
|----------|------------------|-----------------|-------|
| both | `/tmp/bbfdm/.bbfdm/config/` | `/tmp/bbfdm/.bbfdm/dmmap/` | 0 |
| cwmp | `/tmp/bbfdm/.cwmp/config/` | `/tmp/bbfdm/.cwmp/dmmap/` | 1 |
| usp | `/tmp/bbfdm/.usp/config/` | `/tmp/bbfdm/.usp/dmmap/` | 2 |
#### UCI Integration
- **Standard UCI Path**: `/etc/config/`
- **DMMAP UCI Path**: `/etc/bbfdm/dmmap/`
- **Operations**: Commit, revert, and list configurations
- **Persistence**: Changes saved to protocol-specific directories
### Service Management
#### Service Monitoring
- **Validation**: Checks if services are properly reloaded after configuration changes
- **Criteria**:
- Instance status changes (running/stopped)
- Process ID (PID) changes
- Instance count changes
- **Timeout**: Configurable wait time for service reload validation
#### Critical Services
- **Definition File**: `/etc/bbfdm/critical_services.json`
- **Purpose**: Identifies services that require monitoring during configuration changes
- **Effect**: Enables asynchronous request handling with validation
#### External Handlers
- **Configuration Path**: `/etc/bbfdm/services/`
- **Types**: DMMAP and UCI handlers
- **Default Handler**: `/etc/bbfdm/bbf_default_reload.sh`
- **Purpose**: Custom scripts for service-specific configuration handling
##### Example and Explanation
```json
{
"daemon": {
"enable": "1",
"service_name": "xxxx",
"unified_daemon": true,
"services": [
{
"parent_dm": "Device.",
"object": "XXXX"
}
],
"config": {
"loglevel": "3"
},
"apply_handler": {
"uci": [
{
"file": [
"xxxx",
"yyyy"
],
"external_handler": "/etc/xxxx/bbf_config_reload.sh"
}
],
"dmmap": [
{
"file": [
"zzzz"
],
"external_handler": "/etc/xxxx/bbf_dmmap_handler.sh"
}
]
}
}
}
``` ```
#### bbf.config commit method:
This method commits configuration changes to the specified services based on the given `proto` option (protocol). It reloads services according to `reload` option but handles critical services differently. - If external component asks to commit UCI file 'xxxx' or 'yyyy' or both then this module will commit the changes from protocol based UCI save directory to the standard UCI and will execute the script provided in the `external_handler` field. If no external handler is provided then it will execute default reload handler script `/etc/bbfdm/bbf_default_reload.sh`.
- If there is any change in the dmmap file `zzzz` and a commit request has been received then this module will commit the changes in standard dmmap file from the protocol based dmmap directory and if any external handler is given like in above example then it will execute that script. Services may use this handler script to perform any desired tasks on changes in the dmmap file.
The Critical services are defined in `/etc/bbfdm/critical_services.json` file. ### Operational Flow
- If a service is critical, the process waits until the service's timeout expires or the service's PID changes and then it does reload the service.
- Non-critical services are reloaded immediately.
Critical Services File #### Commit Operation
1. Parse incoming UBUS request parameters
2. Load critical services configuration
3. If monitoring required, capture current service states
4. Process configuration changes:
- Specific services: Process only requested services
- All services: Process all modified configurations
5. Execute external handlers for affected services if any otherwise default handler
6. If monitoring enabled:
- Defer response and validate service reloads
- Send response after validation or timeout
7. Send bbfdm.apply event with list of all modified UCI names
8. Clean up allocated resources
The following file defines critical services for each protocol: #### Revert Operation
1. Parse incoming UBUS request parameters
2. Revert UCI changes for specified or all services
4. Return immediate success response
#### Flow Diagram
```mermaid
flowchart TD
A[Start bbf_configd] --> B[Parse command line args]
B --> C[Initialize ulog & uloop]
C --> D[Connect to UBUS]
D --> E[Load critical services JSON]
E --> F[Load apply handlers from /etc/bbfdm/services]
F --> G[Register UBUS object 'bbf.config']
G --> H[Register event handler 'bbf.config.notify']
H --> I[Enter uloop_run - Wait for requests]
I --> J{Incoming Request}
J -->|commit| K[bbf_config_commit_handler]
J -->|revert| L[bbf_config_revert_handler]
J -->|notify event| M[receive_notify_event]
%% Commit Handler Flow
K --> K1[Parse blob message]
K1 --> K2[Allocate async request structure]
K2 --> K3[Determine protocol index from 'proto']
K3 --> K4[Get monitor status for critical services]
K4 --> K5{Monitor required?}
K5 -->|Yes| K6[Get current service info via UBUS]
K5 -->|No| K7[Process services]
K6 --> K7
K7 --> K8{Services specified?}
K8 -->|Yes| K9[commit specified configs]
K8 -->|No| K10[commit all config changes]
K9 --> K11[Execute action scripts]
K10 --> K11
K11 --> K12{Monitor enabled?}
K12 -->|Yes| K13[Defer request & set timeout]
K12 -->|No| K14[Send immediate reply]
K13 --> K15[validate_required_services]
K15 --> K16{Services reloaded?}
K16 -->|Yes| K17[Complete request, send reply]
K16 -->|No| K18[Wait & retry]
K18 --> K17
K14 --> K20[Send bbfdm.apply event]
K17 --> K19[Sync with externally changed uci list]
K19 --> K20
K20 --> I
%% Revert Handler Flow
L --> L1[Parse blob message]
L1 --> L2[Determine protocol index]
L2 --> L3{Services specified?}
L3 -->|Yes| L4[revert specified_services]
L3 -->|No| L5[revert all services]
L4 --> L6[Send reply]
L5 --> L6
L6 --> I
%% Notify Event Flow
M --> M1[Parse config name from event]
M1 --> M2{Internal commit in progress?}
M2 -->|Yes| M3[Add to global external changed list]
M2 -->|No| M4[Send immediate bbfdm.apply event]
M3 --> I
M4 --> I
%% Service Processing Detail
subgraph SP[Service Processing Details]
SP1[commit services] --> SP2[For each service]
SP2 --> SP3[Determine UCI path & save directory]
SP3 --> SP4[Set UCI context directories]
SP4 --> SP5[Lookup UCI pointer]
SP5 -->|Commit| SP6[uci_commit]
SP6 --> SP7[Add specific action to action list]
SP7 --> SP8[Add to changed UCI list if not DMMAP]
end
%% UBUS Service Info Gathering
subgraph SG[Service Info Gathering]
SG1[fill_service_info] --> SG2[Call service.list via UBUS]
SG2 --> SG3[_get_service_list_cb or _get_specific_service_cb]
SG3 --> SG4[Parse service instances & triggers]
SG4 --> SG5[Build config package structure]
end
K6 -.-> SG1
K15 -.-> SG1
K9 -.-> SP1
K10 -.-> SP1
style K fill:#e1f5fe
style L fill:#f3e5f5
style M fill:#e8f5e8
style K13 fill:#fff3e0
style K20 fill:#fce4ec
```
### Error Handling
#### Common Error Scenarios
- **Memory Allocation Failures**: Proper cleanup and error responses
- **UCI Operation Failures**: Logging and graceful continuation
- **UBUS Communication Errors**: Timeout handling and retries
- **Service Validation Timeouts**: Fallback completion after maximum wait time
### Configuration Files
#### Critical Services Definition (`critical_services.json`)
```json
{
"cwmp": ["cwmp_service"],
"usp": ["usp_service"]
}
```
##### Example
```bash ```bash
cat /etc/bbfdm/critical_services.json cat /etc/bbfdm/critical_services.json
{ {
"usp": [ "usp": [
"firewall", "/etc/config/mapcontroller",
"network", "/etc/config/wireless",
"dhcp", "/etc/bbfdm/dmmap/WiFi",
"wireless", ...
"time" ...
], ],
"cwmp": [ "cwmp": [
"firewall", "/etc/config/mapcontroller",
"network", "/etc/config/wireless",
"dhcp", "/etc/bbfdm/dmmap/WiFi",
"stunc", ...
"xmpp", ...
"wireless",
"time"
] ]
} }
``` ```
#### bbf.config revert method: #### Service Configuration for apply handler (`services/*.json`)
this method commits the changes in the required services based on proto option. ```json
#### bbf.config changes method:
this method provides the list of certical services based on protocol (proto option) and provide the available config changes based on protocol.
```bash
ubus call bbf.config changes '{"proto":"usp"}'
{ {
"configs": [ "daemon": {
"users", "enable": "0 or 1",
"wireless" "service_name": "name_of_the_service",
...
...
"apply_handler": {
"uci": [
{
"file": ["config_name"],
"external_handler": "/path/to/handler.sh"
}
], ],
"critical_services": [ "dmmap": [
"firewall", {
"network", "file": ["dmmap_file"],
"dhcp", "external_handler": "/path/to/dmmap_handler.sh"
"wireless", }
"time"
] ]
} }
}
}
``` ```
### Usage
#### UBUS Commands
```bash
# Commit all changes
ubus call bbf.config commit '{"proto":"both", "reload":true}'
# Commit specific services
ubus call bbf.config commit '{"services":["network","wireless"], "proto":"both"}'
# Revert all changes
ubus call bbf.config revert '{"proto":"both"}'
# Revert specific services
ubus call bbf.config revert '{"services":["network"], "proto":"both"}'
```
### Dependencies
#### Libraries
- `libubox`: UBUS and event loop functionality
- `libuci`: UCI configuration management
- `json-c`: JSON parsing for configuration files
- `libc`: Standard C library functions
#### System Requirements
- OpenWrt-based system
- UBUS daemon running
- UCI system configured
- Proper directory structure for configuration files

View file

@ -1,144 +0,0 @@
#!/bin/sh
. /usr/share/libubox/jshn.sh
BBFDM_CONFIG_CONFDIR="/etc/config"
BBFDM_DMMAP_CONFDIR="/etc/bbfdm/dmmap"
BBFDM_CONFIG_SAVEDIR="/tmp/bbfdm/.bbfdm/config"
BBFDM_DMMAP_SAVEDIR="/tmp/bbfdm/.bbfdm/dmmap"
LOGLEVEL="$(uci -q get bbfdm.bbfdmd.loglevel)"
log() {
local level
level="${LOGLEVEL:-0}"
if [ "${level}" -gt 2 ]; then
echo "$@" | logger -t bbf.config -p info
fi
}
check_result() {
local res="$1"
local service="$2"
local action="$3"
if [ "${res}" -ne 0 ]; then
echo "{ \"error\": \"Failed to ${action} ${service} service\" }"
exit "${res}"
fi
}
apply_config_changes() {
local service="$1"
local action="$3"
local reload="$4"
# Check if either service or action is empty
if [ -z "$service" ] || [ -z "$action" ]; then
return
fi
log "Applying $action configuration for service: $service"
# Commit/Revert config changes
log "Applying ${action} configuration for file: ${service}"
uci -q -c "${BBFDM_CONFIG_CONFDIR}" -t "${BBFDM_CONFIG_SAVEDIR}" "${action}" "${service}"
check_result "$?" "${service}" "${action}"
if [ "${reload}" == "1" ]; then
# Reload service
ubus -t 1 call uci "${action}" "{'config': '${service}'}"
check_result "$?" "${service}" "${action}"
fi
}
case "$1" in
list)
echo '{ "commit": { "services": [], "proto": "str", "monitor": true, "reload": true }, "revert": { "services": [], "proto": "str", "monitor": true, "reload": true }, "changes": { "proto": "str" } }'
;;
call)
# Read input JSON from standard input
read -r input
# Parse input JSON
json_load "${input}"
# Get the 'proto' value from the input JSON
json_get_var proto proto
if [ "${proto}" == "cwmp" ]; then
BBFDM_CONFIG_SAVEDIR="/tmp/bbfdm/.cwmp/config"
BBFDM_DMMAP_SAVEDIR="/tmp/bbfdm/.cwmp/dmmap"
elif [ "${proto}" == "usp" ]; then
BBFDM_CONFIG_SAVEDIR="/tmp/bbfdm/.usp/config"
BBFDM_DMMAP_SAVEDIR="/tmp/bbfdm/.usp/dmmap"
fi
case "$2" in
commit|revert)
# Get the 'reload' value from the input JSON
json_get_var reload reload
json_get_var monitor monitor
if [ -z "${reload}" ]; then
reload=1
else
if [ "${reload}" != "0" ] && [ "${reload}" != "1" ]; then
echo '{ "error": "Reload should be boolean type !!!" }'
exit 1
fi
fi
# Check if 'services' array is provided
json_get_type type "services"
if [ -z "${type}" ]; then
# Iterate over all services and apply config changes
for config in $(uci -q -c "${BBFDM_CONFIG_CONFDIR}" -t "${BBFDM_CONFIG_SAVEDIR}" changes | awk -F'.' '{print $1}' | sort | uniq); do
apply_config_changes "${config}" "" "$2" "$reload"
done
else
# Check if 'services' is array
if [ "${type}" != "array" ]; then
echo '{ "error": "Services argument should be array of strings !!!" }'
exit 1
fi
# Iterate over each service and apply config changes
json_for_each_item "apply_config_changes" "services" "$2" "$reload"
fi
if [ "${reload}" == "1" ]; then
# Commit/Revert bbfdm dmmap config changes
if [ -d "${BBFDM_DMMAP_SAVEDIR}" ] && [ "$(ls -A "${BBFDM_DMMAP_SAVEDIR}" 2>/dev/null)" ]; then
for file in "${BBFDM_DMMAP_SAVEDIR}"/*; do
file_name=$(basename "${file}")
log "Applying $2 configuration for file: $file_name"
uci -q -c "${BBFDM_DMMAP_CONFDIR}" -t "${BBFDM_DMMAP_SAVEDIR}" "$2" "${file_name}"
check_result "$?" "${file_name}" "$2"
done
fi
fi
if [ "${monitor}" -eq "1" ]; then
sleep 3
fi
# Send 'bbf.config.change' event to run refresh instances
ubus send bbf.config.change
echo '{ "status": "ok" }'
;;
changes)
json_init
json_add_array "configs"
for config in $(uci -q -c "${BBFDM_CONFIG_CONFDIR}" -t "${BBFDM_CONFIG_SAVEDIR}" changes | awk -F'.' '{print $1}' | sort | uniq); do
json_add_string "" "${config}"
done
json_close_array
json_dump
;;
esac
;;
esac

View file

@ -7,6 +7,22 @@
# #
# Send 'bbf.config.notify' event to notify about the 'config.change' from external configs # Send 'bbf.config.notify' event to notify about the 'config.change' from external configs
ubus send bbf.config.notify . /usr/share/libubox/jshn.sh
config="${1}"
if [ -z "${config}" ]; then
exit 0
fi
json_init
json_add_string "config" "${config}"
json_compact
json_data=$(json_dump)
ubus send bbf.config.notify "${json_data}"
json_cleanup
exit 0 exit 0

View file

@ -30,6 +30,8 @@
#define CRITICAL_DEF_JSON "/etc/bbfdm/critical_services.json" #define CRITICAL_DEF_JSON "/etc/bbfdm/critical_services.json"
#define BBFDM_MICROSERVICE_INPUT_PATH "/etc/bbfdm/services" #define BBFDM_MICROSERVICE_INPUT_PATH "/etc/bbfdm/services"
static struct list_head g_external_changed_uci;
// Structure to represent an instance of a service // Structure to represent an instance of a service
struct instance { struct instance {
char name[NAME_LENGTH]; char name[NAME_LENGTH];
@ -461,28 +463,10 @@ wait:
return false; return false;
} }
static void send_bbf_config_change_event()
{
struct ubus_context *ctx;
struct blob_buf bb = {0};
ctx = ubus_connect(NULL);
if (ctx == NULL) {
ULOG_ERR("Can't create UBUS context for 'bbf.config.change' event");
return;
}
ULOG_INFO("Sending bbf.config.change event");
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
ubus_send_event(ctx, "bbf.config.change", bb.head);
blob_buf_free(&bb);
ubus_free(ctx);
}
static void send_bbf_apply_event(int idx, struct list_head *changed_uci_list) static void send_bbf_apply_event(int idx, struct list_head *changed_uci_list)
{ {
char protocol[16] = {0};
if (changed_uci_list == NULL || list_empty(changed_uci_list)) if (changed_uci_list == NULL || list_empty(changed_uci_list))
return; return;
@ -493,7 +477,9 @@ static void send_bbf_apply_event(int idx, struct list_head *changed_uci_list)
memset(&bb, 0, sizeof(struct blob_buf)); memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0); blob_buf_init(&bb, 0);
blobmsg_add_string(&bb, "proto", get_proto_name_by_idx(idx)); snprintf(protocol, sizeof(protocol), "%s", (idx == -1) ? "external" : get_proto_name_by_idx(idx));
blobmsg_add_string(&bb, "proto", protocol);
void *array = blobmsg_open_array(&bb, "uci_changed"); void *array = blobmsg_open_array(&bb, "uci_changed");
list_for_each_entry_safe(node, tmp, changed_uci_list, list) { list_for_each_entry_safe(node, tmp, changed_uci_list, list) {
if (node->uci == NULL) { if (node->uci == NULL) {
@ -546,8 +532,22 @@ static void complete_deferred_request(struct bbf_config_async_req *async_req)
// Complete the deferred request and send the response // Complete the deferred request and send the response
ubus_complete_deferred_request(async_req->ctx, &async_req->req, 0); ubus_complete_deferred_request(async_req->ctx, &async_req->req, 0);
// Send 'bbf.config.change' event to run refresh instances // If any uci is changed externally then add it in bbf.apply event
send_bbf_config_change_event(); struct modi_uci_node *node = NULL, *tmp = NULL;
list_for_each_entry_safe(node, tmp, &g_external_changed_uci, list) {
if (node->uci == NULL) {
list_del(&node->list);
FREE(node);
continue;
}
add_changed_uci_list(&async_req->changed_uci_list, node->uci);
list_del(&node->list);
FREE(node->uci);
FREE(node);
}
// Send 'bbf.apply' event
send_bbf_apply_event(async_req->idx, &async_req->changed_uci_list); send_bbf_apply_event(async_req->idx, &async_req->changed_uci_list);
// Free the allocated memory // Free the allocated memory
@ -766,8 +766,7 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec
ULOG_INFO("Sending immediate success response"); ULOG_INFO("Sending immediate success response");
send_reply(ctx, req, "status", "ok"); send_reply(ctx, req, "status", "ok");
// Send 'bbf.config.change' event to run refresh instances // Send 'bbf.apply' event
send_bbf_config_change_event();
send_bbf_apply_event(idx, changed_uci); send_bbf_apply_event(idx, changed_uci);
// Free the allocated memory // Free the allocated memory
@ -820,25 +819,59 @@ static int bbf_config_revert_handler(struct ubus_context *ctx, struct ubus_objec
ULOG_INFO("Sending success response"); ULOG_INFO("Sending success response");
send_reply(ctx, req, "status", "ok"); send_reply(ctx, req, "status", "ok");
// Send 'bbf.config.change' event to run refresh instances
send_bbf_config_change_event();
ULOG_INFO("revert handler exit"); ULOG_INFO("revert handler exit");
return 0; return 0;
} }
static void free_changed_uci_list(struct list_head *uci_list)
{
struct modi_uci_node *node = NULL, *tmp = NULL;
if (uci_list == NULL)
return;
list_for_each_entry_safe(node, tmp, uci_list, list) {
list_del(&node->list);
FREE(node->uci);
FREE(node);
}
}
static void receive_notify_event(struct ubus_context *ctx, struct ubus_event_handler *ev, static void receive_notify_event(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg) const char *type, struct blob_attr *msg)
{ {
// Skip sending 'bbf.config.change' event if triggered by an internal commit char file_path[1024] = {0};
struct blob_attr *tb[1] = {0};
const struct blobmsg_policy p[1] = {
{ "config", BLOBMSG_TYPE_STRING }
};
blobmsg_parse(p, 1, tb, blob_data(msg), blob_len(msg));
if (!tb[0])
return;
char *config = blobmsg_get_string(tb[0]);
snprintf(file_path, sizeof(file_path), "/etc/config/%s", config);
if (g_internal_commit) { if (g_internal_commit) {
ULOG_DEBUG("Event triggered by internal commit; skipping 'bbf.config.change' event transmission"); ULOG_DEBUG("internal commit in progress, add uci in global list");
add_changed_uci_list(&g_external_changed_uci, file_path);
return; return;
} }
// Trigger 'bbf.config.change' event to refresh instances as required // Trigger 'bbfdm.apply' event
send_bbf_config_change_event(); struct list_head uci_list;
INIT_LIST_HEAD(&uci_list);
add_changed_uci_list(&uci_list, file_path);
send_bbf_apply_event(-1, &uci_list);
free_changed_uci_list(&uci_list);
return;
} }
static const struct ubus_method bbf_config_methods[] = { static const struct ubus_method bbf_config_methods[] = {
@ -1071,6 +1104,8 @@ int main(int argc, char **argv)
load_critical_services(); load_critical_services();
load_apply_handlers(); load_apply_handlers();
INIT_LIST_HEAD(&g_external_changed_uci);
if (ubus_add_object(uctx, &bbf_config_object)) { if (ubus_add_object(uctx, &bbf_config_object)) {
ULOG_ERR("Failed to add 'bbf.config' ubus object"); ULOG_ERR("Failed to add 'bbf.config' ubus object");
goto exit; goto exit;
@ -1085,6 +1120,7 @@ int main(int argc, char **argv)
exit: exit:
free_apply_handlers(); free_apply_handlers();
free_changed_uci_list(&g_external_changed_uci);
blob_buf_free(&g_critical_bb); blob_buf_free(&g_critical_bb);
uloop_done(); uloop_done();
ubus_free(uctx); ubus_free(uctx);

View file

@ -136,7 +136,7 @@ static void add_external_action_list(struct list_head *action_list, struct list_
} }
} }
static void add_changed_uci_list(struct list_head *changed_uci, const char *file_path) void add_changed_uci_list(struct list_head *changed_uci, const char *file_path)
{ {
if (changed_uci == NULL || file_path == NULL || strlen(file_path) == 0) if (changed_uci == NULL || file_path == NULL || strlen(file_path) == 0)
return; return;

View file

@ -78,5 +78,6 @@ const char *get_proto_dmmap_savedir_by_idx(int idx);
const char *get_proto_name_by_idx(int idx); const char *get_proto_name_by_idx(int idx);
bool file_exists(const char *path); bool file_exists(const char *path);
bool regular_file(const char *path); bool regular_file(const char *path);
void add_changed_uci_list(struct list_head *changed_uci, const char *file_path);
#endif //__UTILS_H__ #endif //__UTILS_H__