From 379f492041b2ebde3910d954f98d2dec96b70ff9 Mon Sep 17 00:00:00 2001 From: Amin Ben Romdhane Date: Tue, 6 Feb 2024 06:20:59 +0000 Subject: [PATCH] T#13540: Support Overwriting/Disabling/Extending core datamodel using JSON Plugins --- docs/guide/libbbfdm-api_vendor.md | 11 +-- libbbfdm-api/dmplugin.c | 40 +++++++--- libbbfdm-api/dmplugin.h | 3 +- libbbfdm-api/plugin/json_plugin.c | 111 ++++++++++++++++++--------- test/vendor_test/test_exclude.json | 64 +++++++++++---- test/vendor_test/test_extend.json | 57 ++++++++++++++ test/vendor_test/test_overwrite.json | 27 ++++++- 7 files changed, 243 insertions(+), 70 deletions(-) diff --git a/docs/guide/libbbfdm-api_vendor.md b/docs/guide/libbbfdm-api_vendor.md index 2e1f5be1..abdafc07 100644 --- a/docs/guide/libbbfdm-api_vendor.md +++ b/docs/guide/libbbfdm-api_vendor.md @@ -53,7 +53,8 @@ In the [test/vendor_test/](../../test/vendor_test) directory, you'll find an exa - Add support for [Device.Firewall.Chain.{i}.Rule.{i}.X_TEST_COM_ICMPType](../../test/vendor_test/firewall.c#L178) parameter - using JSON Plugin: - - Add support for [Device.PD2.{i}.](../../test/vendor_test/test_extend.json) object + - Add support for [Device.PD2.{i}.](../../test/vendor_test/test_extend.json#L59) object + - Add support for [Device.WiFi.X_IOPSYS_EU_TEST1](../../test/vendor_test/test_extend.json#L10) parameter ### 2. Overwrite Data Model @@ -62,7 +63,8 @@ In the [test/vendor_test/](../../test/vendor_test) directory, you'll find an exa - Overwrite [Device.DeviceInfo.Manufacturer](../../test/vendor_test/deviceinfo.c#L29) parameter in the core tree - using JSON Plugin: - - Overwrite [Device.DeviceInfo.Processor.](../../test/vendor_test/test_overwrite.json) object in the core tree + - Overwrite [Device.DeviceInfo.Processor.](../../test/vendor_test/test_overwrite.json#L10) object in the core tree + - Overwrite [Device.DeviceInfo.ProcessorNumberOfEntries](../../test/vendor_test/test_overwrite.json#L29) parameter in the core tree ### 3. Exclude Data Model @@ -71,11 +73,10 @@ In the [test/vendor_test/](../../test/vendor_test) directory, you'll find an exa - Exclude [Device.Ethernet.RMONStats.{i}.Packets1024to1518Bytes](../../test/vendor_test/extension.c#L37) parameter from the core tree - using JSON Plugin: - - Exclude [Device.X_IOPSYS_EU_IGMP.](../../test/vendor_test/test_exclude.json) object from the core tree + - Exclude [Device.X_IOPSYS_EU_IGMP.](../../test/vendor_test/test_exclude.json#L27) object from the core tree + - Exclude [Device.InterfaceStackNumberOfEntries](../../test/vendor_test/test_exclude.json#L51) parameter from the core tree > Note1: The `libbbfdm` vendor list can support multiple vendors, separated by commas. > Note2: If multi vendors are supported and there is an objects/parameters/operates/events implemented differently by different vendors, the implementation of the **last vendor name** in **BBF_VENDOR_LIST** will be considered. - -> Note3: In the JSON plugin, there is no way to extend, overwrite and exclude parameters/operates/events that have an existing object in the core tree. diff --git a/libbbfdm-api/dmplugin.c b/libbbfdm-api/dmplugin.c index c5e4dd48..f81f1739 100644 --- a/libbbfdm-api/dmplugin.c +++ b/libbbfdm-api/dmplugin.c @@ -49,7 +49,7 @@ static bool add_service_to_main_tree(DMOBJ *main_dm, char *srv_name, char *srv_p ((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).obj = dm_dynamic_strdup(&global_memhead, srv_obj); ((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[0]).checkdep = dm_dynamic_strdup(&global_memhead, srv_name); } else { - int idx = get_entry_idx(dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0]); + int idx = get_entry_obj_idx(dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0]); dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] = dm_dynamic_realloc(&global_memhead, dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0], (idx + 2) * sizeof(struct dm_obj_s)); memset(dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0] + (idx + 1), 0, sizeof(struct dm_obj_s)); ((dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].nextobj[0])[idx]).obj = dm_dynamic_strdup(&global_memhead, srv_obj); @@ -335,12 +335,17 @@ void disable_entry_obj(DMOBJ *entryobj, char *obj_path, const char *parent_obj, if (!entryobj || !plugin_path || DM_STRLEN(obj_path) == 0) return; + char obj_name[256] = {0}; + replace_str(obj_path, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, obj_name, sizeof(obj_name)); + if (strlen(obj_name) == 0) + return; + DMOBJ *nextobj = entryobj->nextobj; for (; (nextobj && nextobj->obj); nextobj++) { - if (DM_STRCMP(nextobj->obj, obj_path) == 0) { - BBF_INFO("## Excluding [%s%s.] from the core tree and the same object will be exposed again using (%s) ##", parent_obj, obj_path, plugin_path); + if (DM_STRCMP(nextobj->obj, obj_name) == 0) { + BBF_INFO("## Excluding [%s%s.] from the core tree and the same object will be exposed again using (%s) ##", parent_obj, obj_name, plugin_path); nextobj->bbfdm_type = BBFDM_NONE; return; } @@ -354,8 +359,8 @@ void disable_entry_obj(DMOBJ *entryobj, char *obj_path, const char *parent_obj, DMOBJ *jentryobj = next_dyn_array->nextobj[j]; for (; (jentryobj && jentryobj->obj); jentryobj++) { - if (DM_STRCMP(jentryobj->obj, obj_path) == 0) { - TRACE("## Excluding [%s%s.] from the core tree and the same object will be exposed again using (%s) ##", parent_obj, obj_path, plugin_path); + if (DM_STRCMP(jentryobj->obj, obj_name) == 0) { + BBF_INFO("## Excluding [%s%s.] from the core tree and the same object will be exposed again using (%s) ##", parent_obj, obj_name, plugin_path); jentryobj->bbfdm_type = BBFDM_NONE; return; } @@ -371,12 +376,17 @@ void disable_entry_leaf(DMOBJ *entryobj, char *leaf_path, const char *parent_obj if (!entryobj || !plugin_path || DM_STRLEN(leaf_path) == 0) return; + char leaf_name[256] = {0}; + replace_str(leaf_path, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, leaf_name, sizeof(leaf_name)); + if (strlen(leaf_name) == 0) + return; + DMLEAF *leaf = entryobj->leaf; for (; (leaf && leaf->parameter); leaf++) { - if (DM_STRCMP(leaf->parameter, leaf_path) == 0) { - BBF_INFO("## Excluding [%s%s] from the core tree and the same parameter will be exposed again using (%s) ##", parent_obj, leaf_path, plugin_path); + if (DM_STRCMP(leaf->parameter, leaf_name) == 0) { + BBF_INFO("## Excluding [%s%s] from the core tree and the same parameter will be exposed again using (%s) ##", parent_obj, leaf_name, plugin_path); leaf->bbfdm_type = BBFDM_NONE; return; } @@ -390,8 +400,8 @@ void disable_entry_leaf(DMOBJ *entryobj, char *leaf_path, const char *parent_obj DMLEAF *jleaf = next_dyn_array->nextleaf[j]; for (; (jleaf && jleaf->parameter); jleaf++) { - if (DM_STRCMP(jleaf->parameter, leaf_path) == 0) { - TRACE("## Excluding [%s%s] from the core tree and the same parameter will be exposed again using (%s) ##", parent_obj, leaf_path, plugin_path); + if (DM_STRCMP(jleaf->parameter, leaf_name) == 0) { + BBF_INFO("## Excluding [%s%s] from the core tree and the same parameter will be exposed again using (%s) ##", parent_obj, leaf_name, plugin_path); jleaf->bbfdm_type = BBFDM_NONE; return; } @@ -402,7 +412,7 @@ void disable_entry_leaf(DMOBJ *entryobj, char *leaf_path, const char *parent_obj } } -int get_entry_idx(DMOBJ *entryobj) +int get_entry_obj_idx(DMOBJ *entryobj) { int idx = 0; @@ -412,6 +422,16 @@ int get_entry_idx(DMOBJ *entryobj) return idx; } +int get_entry_leaf_idx(DMLEAF *entryleaf) +{ + int idx = 0; + + for (; (entryleaf && entryleaf->parameter); entryleaf++) + idx++; + + return idx; +} + int get_obj_idx(DMOBJ **entryobj) { int idx = 0; diff --git a/libbbfdm-api/dmplugin.h b/libbbfdm-api/dmplugin.h index 37ad7d93..b60b9abe 100644 --- a/libbbfdm-api/dmplugin.h +++ b/libbbfdm-api/dmplugin.h @@ -16,7 +16,8 @@ DMOBJ *find_entry_obj(DMOBJ *entryobj, char *obj_path); void disable_entry_obj(DMOBJ *entryobj, char *obj_path, const char *parent_obj, const char *plugin_path); void disable_entry_leaf(DMOBJ *entryobj, char *leaf_path, const char *parent_obj, const char *plugin_path); -int get_entry_idx(DMOBJ *entryobj); +int get_entry_obj_idx(DMOBJ *entryobj); +int get_entry_leaf_idx(DMLEAF *entryleaf); int get_obj_idx(DMOBJ **entryobj); int get_leaf_idx(DMLEAF **entryleaf); diff --git a/libbbfdm-api/plugin/json_plugin.c b/libbbfdm-api/plugin/json_plugin.c index bdd33cf9..97f749af 100644 --- a/libbbfdm-api/plugin/json_plugin.c +++ b/libbbfdm-api/plugin/json_plugin.c @@ -1863,6 +1863,54 @@ void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, int json } } +static void create_parse_obj(DMOBJ *dm_entryobj, char *obj_path, json_object *jobj, int json_plugin_version) +{ + if (dm_entryobj->nextdynamicobj == NULL) { + dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj)); + dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT; + dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT; + dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT; + } + + if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj == NULL) { + dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj = calloc(2, sizeof(struct dm_obj_s *)); + } + + if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] == NULL) { + dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] = dm_dynamic_calloc(&json_memhead, 2, sizeof(struct dm_obj_s)); + parse_obj(obj_path, jobj, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], 0, json_plugin_version, &json_list); + } else { + int idx = get_entry_obj_idx(dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0]); + dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] = dm_dynamic_realloc(&json_memhead, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], (idx + 2) * sizeof(struct dm_obj_s)); + memset(dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] + (idx + 1), 0, sizeof(struct dm_obj_s)); + parse_obj(obj_path, jobj, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], idx, json_plugin_version, &json_list); + } +} + +static void create_parse_param(DMOBJ *dm_entryobj, char *obj_path, char *param, json_object *jobj, int json_plugin_version) +{ + if (dm_entryobj->dynamicleaf == NULL) { + dm_entryobj->dynamicleaf = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj)); + dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT; + dm_entryobj->dynamicleaf[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT; + dm_entryobj->dynamicleaf[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT; + } + + if (dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf == NULL) { + dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf = calloc(2, sizeof(struct dm_leaf_s *)); + } + + if (dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0] == NULL) { + dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0] = dm_dynamic_calloc(&json_memhead, 2, sizeof(struct dm_leaf_s)); + parse_param(obj_path, param, jobj, dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0], 0, json_plugin_version, &json_list); + } else { + int idx = get_entry_leaf_idx(dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0]); + dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0] = dm_dynamic_realloc(&json_memhead, dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0], (idx + 2) * sizeof(struct dm_leaf_s)); + memset(dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0] + (idx + 1), 0, sizeof(struct dm_leaf_s)); + parse_param(obj_path, param, jobj, dm_entryobj->dynamicleaf[INDX_JSON_MOUNT].nextleaf[0], idx, json_plugin_version, &json_list); + } +} + int load_json_plugins(DMOBJ *entryobj, const char *plugin_path) { int json_plugin_version = JSON_VERSION_0; @@ -1892,47 +1940,40 @@ int load_json_plugins(DMOBJ *entryobj, const char *plugin_path) continue; } - char obj_prefix[MAX_DM_LENGTH] = {0}; - json_plugin_find_prefix_obj(obj_path, obj_prefix, MAX_DM_LENGTH); - if (strlen(obj_prefix) == 0) { - BBF_DEBUG("ERROR: Obj prefix is empty for (%s) Object", obj_path); - continue; - } + DMOBJ *dm_entryobj = find_entry_obj(entryobj, obj_path); + if (dm_entryobj) { // The object is already in the core tree, should check the next level - char curr_obj[128] = {0}; - json_plugin_find_current_obj(obj_path, curr_obj, sizeof(curr_obj)); - if (strlen(curr_obj) == 0) { - BBF_DEBUG("ERROR: Can't get the current object from (%s) parent object", obj_path); - continue; - } + json_object_object_foreach(jobj, opt, json_obj) { - DMOBJ *dm_entryobj = find_entry_obj(entryobj, obj_prefix); - if (!dm_entryobj) { - BBF_DEBUG("ERROR: entry obj doesn't exist for (%s) Object", obj_prefix); - continue; - } + if (json_object_get_type(json_obj) == json_type_object && is_obj(opt, json_obj)) { + char curr_obj[128] = {0}; - disable_entry_obj(dm_entryobj, curr_obj, obj_prefix, plugin_path); + json_plugin_find_current_obj(opt, curr_obj, sizeof(curr_obj)); - if (dm_entryobj->nextdynamicobj == NULL) { - dm_entryobj->nextdynamicobj = calloc(__INDX_DYNAMIC_MAX, sizeof(struct dm_dynamic_obj)); - dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].idx_type = INDX_JSON_MOUNT; - dm_entryobj->nextdynamicobj[INDX_LIBRARY_MOUNT].idx_type = INDX_LIBRARY_MOUNT; - dm_entryobj->nextdynamicobj[INDX_SERVICE_MOUNT].idx_type = INDX_SERVICE_MOUNT; - } + disable_entry_obj(dm_entryobj, curr_obj, obj_path, plugin_path); + create_parse_obj(dm_entryobj, opt, json_obj, json_plugin_version); + } - if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj == NULL) { - dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj = calloc(2, sizeof(struct dm_obj_s *)); - } + if (json_object_get_type(json_obj) == json_type_object && !is_obj(opt, json_obj) && strcmp(opt, "mapping") != 0) { + disable_entry_leaf(dm_entryobj, opt, obj_path, plugin_path); + create_parse_param(dm_entryobj, obj_path, opt, json_obj, json_plugin_version); + } + } + } else { // It's a new object + char obj_prefix[MAX_DM_LENGTH] = {0}; + json_plugin_find_prefix_obj(obj_path, obj_prefix, MAX_DM_LENGTH); + if (strlen(obj_prefix) == 0) { + BBF_DEBUG("ERROR: Obj prefix is empty for (%s) Object", obj_path); + continue; + } - if (dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] == NULL) { - dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] = dm_dynamic_calloc(&json_memhead, 2, sizeof(struct dm_obj_s)); - parse_obj(obj_path, jobj, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], 0, json_plugin_version, &json_list); - } else { - int idx = get_entry_idx(dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0]); - dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] = dm_dynamic_realloc(&json_memhead, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], (idx + 2) * sizeof(struct dm_obj_s)); - memset(dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] + (idx + 1), 0, sizeof(struct dm_obj_s)); - parse_obj(obj_path, jobj, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], idx, json_plugin_version, &json_list); + dm_entryobj = find_entry_obj(entryobj, obj_prefix); + if (!dm_entryobj) { + BBF_DEBUG("ERROR: entry obj doesn't exist for (%s) Object", obj_prefix); + continue; + } + + create_parse_obj(dm_entryobj, obj_path, jobj, json_plugin_version); } } diff --git a/test/vendor_test/test_exclude.json b/test/vendor_test/test_exclude.json index 26302c83..470f8113 100644 --- a/test/vendor_test/test_exclude.json +++ b/test/vendor_test/test_exclude.json @@ -1,26 +1,60 @@ { - "Device.DeviceInfo.ProcessStatus.": { + "Device.DeviceInfo.": { "type": "object", "protocols": [ - "none" + "cwmp", + "usp" ], "access": false, - "array": false + "array": false, + "Device.DeviceInfo.ProcessStatus.": { + "type": "object", + "protocols": [ + "none" + ], + "access": false, + "array": false + } }, - "Device.X_IOPSYS_EU_IGMP.": { + "Device.": { "type": "object", "protocols": [ - "none" + "cwmp", + "usp" ], "access": false, - "array": false - }, - "Device.X_IOPSYS_EU_MLD.": { - "type": "object", - "protocols": [ - "none" - ], - "access": false, - "array": false - } + "array": false, + "Device.{BBF_VENDOR_PREFIX}IGMP.": { + "type": "object", + "protocols": [ + "none" + ], + "access": false, + "array": false + }, + "Device.{BBF_VENDOR_PREFIX}MLD.": { + "type": "object", + "protocols": [ + "none" + ], + "access": false, + "array": false + }, + "Device.InterfaceStack.": { + "type": "object", + "protocols": [ + "none" + ], + "access": false, + "array": false + }, + "InterfaceStackNumberOfEntries": { + "type": "unsignedInt", + "protocols": [ + "none" + ], + "read": true, + "write": false + } + } } diff --git a/test/vendor_test/test_extend.json b/test/vendor_test/test_extend.json index 07f4b62b..d9022901 100644 --- a/test/vendor_test/test_extend.json +++ b/test/vendor_test/test_extend.json @@ -1,4 +1,61 @@ { + "Device.WiFi.": { + "type": "object", + "protocols": [ + "cwmp", + "usp" + ], + "access": false, + "array": false, + "{BBF_VENDOR_PREFIX}TEST1": { + "type": "boolean", + "protocols": [ + "cwmp", + "usp" + ], + "read": true, + "write": true, + "datatype": "boolean", + "mapping": [ + { + "type": "uci", + "uci": { + "file": "wireless", + "section": { + "name": "config" + }, + "option": { + "name": "test1_enable" + } + } + } + ] + }, + "{BBF_VENDOR_PREFIX}TEST2": { + "type": "boolean", + "protocols": [ + "cwmp", + "usp" + ], + "read": true, + "write": true, + "datatype": "boolean", + "mapping": [ + { + "type": "uci", + "uci": { + "file": "wireless", + "section": { + "name": "config" + }, + "option": { + "name": "test1_enable" + } + } + } + ] + } + }, "Device.PD2.{i}.": { "type": "object", "version": "2.14", diff --git a/test/vendor_test/test_overwrite.json b/test/vendor_test/test_overwrite.json index 3d054b14..56873c1c 100644 --- a/test/vendor_test/test_overwrite.json +++ b/test/vendor_test/test_overwrite.json @@ -1,5 +1,5 @@ { - "Device.DeviceInfo.Processor.": { + "Device.DeviceInfo.": { "type": "object", "protocols": [ "cwmp", @@ -7,15 +7,34 @@ ], "access": false, "array": false, - "Architecture": { - "type": "string", + "Device.DeviceInfo.Processor.": { + "type": "object", "protocols": [ "cwmp", "usp" ], + "access": false, + "array": false, + "Architecture": { + "type": "string", + "protocols": [ + "cwmp", + "usp" + ], + "read": true, + "write": false, + "default": "x86_64" + } + }, + "ProcessorNumberOfEntries": { + "type": "unsignedInt", "read": true, "write": false, - "default": "x86_64" + "protocols": [ + "cwmp", + "usp" + ], + "default": "1" } } }