Support to apply non-critical services immediately

From icwmp point of view, services which can cause upstream/wan disruption are critical services and these are applied at the end of the sessions. These services are defined in '/etc/icwmpd/critical_services.json'.
This commit is contained in:
Suvendhu Hansa 2024-08-08 14:32:01 +00:00 committed by IOPSYS Dev
parent dea357d30f
commit 580f923cfc
No known key found for this signature in database
8 changed files with 165 additions and 36 deletions

View file

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <ifaddrs.h>
#include <mxml.h>
#include <libubox/blobmsg_json.h>
#include "common.h"
#include "cwmp_cli.h"
@ -31,15 +32,20 @@ bool cwmp_stop = false;
unsigned int flashsize = 256000000;
struct cwmp *cwmp_main = NULL;
struct session_timer_event *global_session_event = NULL;
static int nbre_services = 0;
static char *list_services[MAX_NBRE_SERVICES] = { 0 };
LIST_HEAD(critical_service_list);
LIST_HEAD(cwmp_memory_list);
LIST_HEAD(services_reload);
struct cwmp_mem {
struct list_head list;
char mem[0];
};
struct cwmp_services {
struct list_head list;
char *service;
};
struct option cwmp_long_options[] = {
{ "boot-event", no_argument, NULL, 'b' },
{ "get-rpc-methods", no_argument, NULL, 'g' },
@ -645,35 +651,121 @@ void icwmp_cleanmem()
/*
* Services Management
*/
void icwmp_init_list_services()
void icwmp_init_critical_services()
{
int i;
struct blob_buf bbuf = {0};
struct blob_attr *cur = NULL;
struct blob_attr *service_list = NULL;
int rem = 0;
nbre_services = 0;
for (i = 0; i < MAX_NBRE_SERVICES; i++)
list_services[i] = NULL;
if (!file_exists(CWMP_CRITICAL_SERVICES))
return;
CWMP_MEMSET(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
if (blobmsg_add_json_from_file(&bbuf, CWMP_CRITICAL_SERVICES) == false) {
CWMP_LOG(WARNING, "The file %s is not a valid JSON file", CWMP_CRITICAL_SERVICES);
blob_buf_free(&bbuf);
return;
}
struct blob_attr *tb_service[1] = {0};
const struct blobmsg_policy p_service[1] = {
{ "services_list", BLOBMSG_TYPE_ARRAY }
};
blobmsg_parse(p_service, 1, tb_service, blobmsg_data(bbuf.head), blobmsg_len(bbuf.head));
if (tb_service[0] == NULL) {
CWMP_LOG(WARNING, "The JSON file %s doesn't contain any service", CWMP_CRITICAL_SERVICES);
blob_buf_free(&bbuf);
return;
}
service_list = tb_service[0];
blobmsg_for_each_attr(cur, service_list, rem) {
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
continue;
char *serv_name = blobmsg_get_string(cur);
if (CWMP_STRLEN(serv_name) == 0)
continue;
struct cwmp_services *serv = malloc(sizeof(struct cwmp_services));
if (serv == NULL)
break;
serv->service = CWMP_STRDUP(serv_name);
list_add(&serv->list, &critical_service_list);
}
blob_buf_free(&bbuf);
}
void icwmp_free_critical_services()
{
struct cwmp_services *serv = NULL, *node = NULL;
list_for_each_entry_safe(serv, node, &critical_service_list, list) {
list_del(&serv->list);
FREE(serv->service);
free(serv);
}
}
bool icwmp_critical_service(const char *service)
{
bool ret = false;
if (CWMP_STRLEN(service) == 0 || list_empty(&critical_service_list))
return ret;
struct cwmp_services *serv = NULL;
list_for_each_entry(serv, &critical_service_list, list) {
if (CWMP_STRCMP(service, serv->service) == 0) {
ret = true;
break;
}
}
return ret;
}
int icwmp_add_service(char *service)
{
if (nbre_services >= MAX_NBRE_SERVICES)
if (CWMP_STRLEN(service) == 0)
return -1;
list_services[nbre_services++] = strdup(service);
struct cwmp_services *serv = malloc(sizeof(struct cwmp_services));
if (serv == NULL)
return -1;
serv->service = CWMP_STRDUP(service);
list_add(&serv->list, &services_reload);
return 0;
}
void icwmp_free_list_services()
{
int i = 0;
for (i = 0; i < nbre_services; i++) {
FREE(list_services[i]);
struct cwmp_services *serv = NULL, *node = NULL;
list_for_each_entry_safe(serv, node, &services_reload, list) {
list_del(&serv->list);
FREE(serv->service);
free(serv);
}
nbre_services = 0;
}
void icwmp_restart_services()
bool end_session_reload_pending()
{
return !list_empty(&services_reload);
}
void icwmp_restart_services(int type)
{
struct blob_buf bb = {0};
struct cwmp_services *serv = NULL, *node = NULL;
memset(&bb, 0, sizeof(struct blob_buf));
@ -681,16 +773,35 @@ void icwmp_restart_services()
void *array = blobmsg_open_array(&bb, "services");
for (int i = 0; i < nbre_services; i++) {
if (list_services[i] == NULL)
list_for_each_entry_safe(serv, node, &services_reload, list) {
if (CWMP_STRLEN(serv->service) == 0) {
list_del(&serv->list);
FREE(serv->service);
free(serv);
continue;
}
// If RELOAD_IMMIDIATE then only reload the non-critical services and delete from the list
// otherwise reload all services in the list and clear the list
if ((type == RELOAD_IMMIDIATE) && (icwmp_critical_service(serv->service) == true)) {
continue;
}
CWMP_LOG(DEBUG, "Detected service: %s will be restarted", serv->service);
if (CWMP_STRCMP(serv->service, "cwmp") == 0) {
list_del(&serv->list);
FREE(serv->service);
free(serv);
if (CWMP_STRCMP(list_services[i], "cwmp") == 0) {
commit_uci_package("cwmp");
continue;
}
blobmsg_add_string(&bb, NULL, list_services[i]);
blobmsg_add_string(&bb, NULL, serv->service);
list_del(&serv->list);
FREE(serv->service);
free(serv);
}
blobmsg_close_array(&bb, array);
@ -698,8 +809,6 @@ void icwmp_restart_services()
icwmp_ubus_invoke("bbf.config", "commit", bb.head, NULL, NULL);
blob_buf_free(&bb);
icwmp_free_list_services();
}
/*

View file

@ -75,6 +75,7 @@
#define ICWMP_TMP_PATH "/tmp/icwmp"
#define FIREWALL_CWMP "/etc/firewall.cwmp"
#define CWMP_CRITICAL_SERVICES "/etc/icwmpd/critical_services.json"
#define DM_PPP_INTERFACE_PATH "Device\\.PPP\\.Interface\\."
#define DM_IP_INTERFACE_PATH "Device\\.IP\\.Interface\\."
#define DEFAULT_CR_TIMEOUT 5 /* In Seconds */
@ -93,6 +94,12 @@ extern struct uloop_timeout retry_session_timer;
extern struct list_head intf_reset_list;
extern struct list_head force_inform_list;
enum service_apply_type {
RELOAD_END_SESSION,
RELOAD_IMMIDIATE,
__INVALID_TYPE
};
typedef struct env {
unsigned short boot;
unsigned short periodic;
@ -647,10 +654,9 @@ char *icwmp_strdup(const char *s);
int icwmp_asprintf(char **s, const char *format, ...);
void icwmp_free(void *m);
void icwmp_cleanmem();
void icwmp_init_list_services();
int icwmp_add_service(char *service);
void icwmp_free_list_services();
void icwmp_restart_services();
void icwmp_free_list_services(void);
void icwmp_restart_services(int type);
bool icwmp_validate_string_length(char *arg, int max_length);
bool icwmp_validate_boolean_value(char *arg);
bool icwmp_validate_unsignedint(char *arg);
@ -687,4 +693,8 @@ void *cwmp_memcpy(void *dst, const void *src, size_t size, const char *origin, i
void cwmp_restart_service(struct uloop_timeout *timeout __attribute__((unused)));
int regex_replace(char **str, const char *pattern, const char *replace, int *match_count);
void stop_service(void);
void icwmp_init_critical_services(void);
void icwmp_free_critical_services(void);
bool end_session_reload_service(const char *service);
bool end_session_reload_pending(void);
#endif

View file

@ -263,7 +263,7 @@ static int cwmp_init(void)
CWMP_LOG(INFO, "STARTING ICWMP with PID :%d", getpid());
icwmp_init_list_services();
icwmp_init_critical_services();
/* Only One instance should run*/
cwmp_main->pid_file = fopen("/var/run/icwmpd.pid", "w+");
@ -335,6 +335,8 @@ static void cwmp_free()
icwmp_cleanmem();
rpc_exit();
clean_cwmp_session_structure();
icwmp_free_critical_services();
icwmp_free_list_services();
FREE(cwmp_main);
CWMP_LOG(INFO, "EXIT ICWMP");
closelog();

View file

@ -101,7 +101,6 @@ static void ubus_transaction_callback(struct ubus_request *req, int type __attri
if (CWMP_STRLEN(service_name) == 0)
continue;
CWMP_LOG(DEBUG, "Detected service: %s will be restarted in the end session", service_name);
icwmp_add_service(service_name);
}
}

View file

@ -1130,6 +1130,19 @@ int cwmp_handle_rpc_cpe_set_parameter_values(struct rpc *rpc)
cwmp_free_all_xml_data_list(&xml_list_set_param_value);
cwmp_free_all_dm_parameter_list(&list_set_param_value);
if (!cwmp_transaction("commit")) {
fault_code = FAULT_CPE_INTERNAL_ERROR;
err_msg = "Failed to commit the transaction";
goto fault;
}
icwmp_restart_services(RELOAD_IMMIDIATE);
int status = 0;
if (end_session_reload_pending() == true) {
status = 1;
}
b = build_top_body_soap_response(cwmp_main->session->tree_out, "SetParameterValues");
if (!b) {
@ -1138,8 +1151,6 @@ int cwmp_handle_rpc_cpe_set_parameter_values(struct rpc *rpc)
goto fault;
}
int status = 1;
struct xml_data_struct spv_resp_xml_attrs = {.status = &status};
fault_code = build_xml_node_data(SOAP_RESP_SPV, b, &spv_resp_xml_attrs);
if (fault_code) {
@ -1147,13 +1158,11 @@ int cwmp_handle_rpc_cpe_set_parameter_values(struct rpc *rpc)
goto fault;
}
if (!cwmp_transaction("commit")) {
fault_code = FAULT_CPE_INTERNAL_ERROR;
err_msg = "Failed to commit the transaction";
goto fault;
cwmp_set_end_session(END_SESSION_SET_NOTIFICATION_UPDATE | END_SESSION_RELOAD);
if (status == 1) {
cwmp_set_end_session(END_SESSION_RESTART_SERVICES);
}
cwmp_set_end_session(END_SESSION_RESTART_SERVICES | END_SESSION_SET_NOTIFICATION_UPDATE | END_SESSION_RELOAD);
return 0;
fault:

View file

@ -645,7 +645,7 @@ int run_session_end_func(void)
if (end_session_flag & END_SESSION_RESTART_SERVICES) {
CWMP_LOG(INFO, "Restart modified services");
icwmp_restart_services();
icwmp_restart_services(RELOAD_END_SESSION);
}
if (cwmp_apply_acs_changes() != CWMP_OK) {

View file

@ -299,7 +299,7 @@ static void soap_add_object_message_test(void **state)
int ret = cwmp_handle_rpc_cpe_add_object(rpc_cpe);
assert_int_equal(ret, 0);
icwmp_restart_services();
icwmp_restart_services(RELOAD_IMMIDIATE);
env = mxmlFindElement(cwmp_main->session->tree_out, cwmp_main->session->tree_out, "soap_env:Envelope", NULL, NULL, MXML_DESCEND);
assert_non_null(env);
@ -451,7 +451,7 @@ static void soap_delete_object_message_test(void **state)
int ret = cwmp_handle_rpc_cpe_delete_object(rpc_cpe);
assert_int_equal(ret, 0);
icwmp_restart_services();
icwmp_restart_services(RELOAD_IMMIDIATE);
env = mxmlFindElement(cwmp_main->session->tree_out, cwmp_main->session->tree_out, "soap_env:Envelope", NULL, NULL, MXML_DESCEND);
assert_non_null(env);

View file

@ -24,7 +24,7 @@ check_ret $?
wait_for_session_end
check_session "SetParameterValues"
get_status=$(print_tag_value "cwmp:SetParameterValuesResponse" "Status")
if [ "$get_status" != "1" ]; then
if [ "$get_status" != "0" ]; then
echo "Error: Set Value doesn't work correctly" >> ./funl-test-debug.log
exit 1
fi