aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/CMakeLists.txt2
-rw-r--r--src/plugins/ietf/ietf_interface.c142
-rw-r--r--src/plugins/ietf/ietf_interface.h39
-rw-r--r--src/plugins/openconfig/openconfig_interfaces.c62
-rw-r--r--src/plugins/openconfig/openconfig_interfaces.h29
-rw-r--r--src/plugins/openconfig/openconfig_local_routing.c61
-rw-r--r--src/plugins/openconfig/openconfig_local_routing.h28
-rw-r--r--src/plugins/openconfig/openconfig_plugin.c267
-rw-r--r--src/plugins/openconfig/openconfig_plugin.h78
-rw-r--r--src/plugins/sc_model.c82
-rw-r--r--src/plugins/sc_model.h67
-rw-r--r--src/plugins/sc_plugins.c142
-rw-r--r--src/plugins/sc_plugins.h4
13 files changed, 399 insertions, 604 deletions
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index a54ebf0..f9bc5ea 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -45,10 +45,10 @@ endif()
# plugins sources
set(PLUGINS_SOURCES
sc_plugins.c
+ sc_model.c
ietf/ietf_interface.c
openconfig/openconfig_interfaces.c
openconfig/openconfig_local_routing.c
- openconfig/openconfig_plugin.c
openconfig/sys_util.c
)
diff --git a/src/plugins/ietf/ietf_interface.c b/src/plugins/ietf/ietf_interface.c
index 74f0272..728d20e 100644
--- a/src/plugins/ietf/ietf_interface.c
+++ b/src/plugins/ietf/ietf_interface.c
@@ -18,8 +18,6 @@
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "ietf_interface.h"
-#include "../sc_plugins.h"
#include <sysrepo.h>
#include <sysrepo/plugins.h>
#include <sysrepo/values.h>
@@ -29,9 +27,39 @@
#include <vnet/ip/ip.h>
#include <vapi/interface.api.vapi.h>
+#include "ietf_interface.h"
DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON;
+typedef struct _s_vpp_interface_
+{
+ u32 sw_if_index;
+ char interface_name[VPP_INTFC_NAME_LEN];
+ u8 l2_address[VPP_MAC_ADDRESS_LEN];
+ u32 l2_address_length;
+ u64 link_speed;
+ u16 link_mtu;
+ u8 admin_up_down;
+ u8 link_up_down;
+} scVppIntfc;
+
+typedef struct _ietf_sw_interface_dump_ctx
+{
+ u8 last_called;
+ int num_ifs;
+ int capacity;
+ scVppIntfc * intfcArray;
+} ietf_sw_interface_dump_ctx;
+
+static i32 ietf_setInterfaceFlags(u32 sw_if_index, u8 admin_up_down);
+static i32 ietf_interface_name2index(const char *name, u32* if_index);
+static i32 ietf_interface_add_del_addr(u32 sw_if_index, u8 is_add, u8 is_ipv6,
+ u8 del_all, u8 address_length,
+ u8 address[VPP_IP6_ADDRESS_LEN]);
+static int ietf_swInterfaceDump(ietf_sw_interface_dump_ctx * dctx);
+static int ietf_initSwInterfaceDumpCTX(ietf_sw_interface_dump_ctx * dctx);
+static int ietf_freeSwInterfaceDumpCTX(ietf_sw_interface_dump_ctx * dctx);
+
/**
* @brief Helper function for converting netmask into prefix length.
*/
@@ -259,7 +287,8 @@ ietf_sw_interface_dump_cb (struct vapi_ctx_s *ctx, void *callback_ctx,
}
return VAPI_OK;
}
-int ietf_swInterfaceDump(ietf_sw_interface_dump_ctx * dctx)
+
+static int ietf_swInterfaceDump(ietf_sw_interface_dump_ctx * dctx)
{
if(dctx == NULL)
{
@@ -282,7 +311,7 @@ int ietf_swInterfaceDump(ietf_sw_interface_dump_ctx * dctx)
return dctx->num_ifs;
}
-i32 ietf_interface_name2index(const char *name, u32* if_index)
+static i32 ietf_interface_name2index(const char *name, u32* if_index)
{
ARG_CHECK2(-1, name, if_index);
@@ -338,6 +367,7 @@ i32 ietf_interface_add_del_addr( u32 sw_if_index, u8 is_add, u8 is_ipv6, u8 del_
vapi_msg_free (g_vapi_ctx_instance, resp);
return ret;
}
+
i32 ietf_setInterfaceFlags(u32 sw_if_index, u8 admin_up_down)
{
i32 ret = -1;
@@ -531,7 +561,11 @@ ietf_interface_change_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_
* @brief Callback to be called by any request for state data under "/ietf-interfaces:interfaces-state/interface" path.
*/
static int
-ietf_interface_state_cb(const char *xpath, sr_val_t **values, size_t *values_cnt, uint64_t request_id, void *private_ctx)
+ietf_interface_state_cb(const char *xpath, sr_val_t **values,
+ size_t *values_cnt,
+ __attribute__((unused)) uint64_t request_id,
+ __attribute__((unused)) const char *original_xpath,
+ __attribute__((unused)) void *private_ctx)
{
sr_val_t *values_arr = NULL;
int values_arr_size = 0, values_arr_cnt = 0;
@@ -610,55 +644,51 @@ ietf_interface_state_cb(const char *xpath, sr_val_t **values, size_t *values_cnt
return SR_ERR_OK;
}
-/**
- * @brief Callback to be called by plugin daemon upon plugin load.
- */
-int
-ietf_interface_subscribe_events(sr_session_ctx_t *session,
- sr_subscription_ctx_t **subscription)
-{
- int rc = SR_ERR_OK;
-
- SRP_LOG_DBG_MSG("Initializing vpp-interfaces plugin.");
-
- rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface",
- ietf_interface_change_cb, g_vapi_ctx_instance, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription);
- if (SR_ERR_OK != rc) {
- goto error;
- }
-
- rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/enabled",
- ietf_interface_enable_disable_cb, g_vapi_ctx_instance, 100, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription);
- if (SR_ERR_OK != rc) {
- goto error;
- }
-
- rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address",
- ietf_interface_ipv46_address_change_cb, g_vapi_ctx_instance, 99, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription);
- if (SR_ERR_OK != rc) {
- goto error;
- }
-
- rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address",
- ietf_interface_ipv46_address_change_cb, g_vapi_ctx_instance, 98, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription);
- if (SR_ERR_OK != rc) {
- goto error;
- }
-
- rc = sr_dp_get_items_subscribe(session, "/ietf-interfaces:interfaces-state",
- ietf_interface_state_cb, g_vapi_ctx_instance, SR_SUBSCR_DEFAULT/*SR_SUBSCR_CTX_REUSE*/, subscription);
- if (SR_ERR_OK != rc) {
- goto error;
+const xpath_t ietf_interfaces_xpaths[IETF_INTERFACES_SIZE] = {
+ {
+ .xpath = "/ietf-interfaces:interfaces/interface",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = ietf_interface_change_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ .opts = SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED
+ },
+ {
+ .xpath = "/ietf-interfaces:interfaces/interface/enabled",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = ietf_interface_enable_disable_cb,
+ .private_ctx = NULL,
+ .priority = 100,
+ .opts = SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED
+ },
+ {
+ .xpath = "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = ietf_interface_ipv46_address_change_cb,
+ .private_ctx = NULL,
+ .priority = 99,
+ .opts = SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED
+ },
+ {
+ .xpath = "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = ietf_interface_ipv46_address_change_cb,
+ .private_ctx = NULL,
+ .priority = 98,
+ .opts = SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED
+ },
+ {
+ .xpath = "/ietf-interfaces:interfaces-state",
+ .method = GETITEM,
+ .datastore = SR_DS_RUNNING,
+ .cb.gcb = ietf_interface_state_cb,
+ .private_ctx = NULL,
+ .priority = 98,
+ //.opts = SR_SUBSCR_DEFAULT,
+ .opts = SR_SUBSCR_CTX_REUSE
}
-
-
- SRP_LOG_INF_MSG("vpp-interfaces plugin initialized successfully.");
-
- return SR_ERR_OK;
-
-error:
- SRP_LOG_ERR_MSG("Error by initialization of the sc_interfaces plugin.");
- sr_plugin_cleanup_cb(session, &g_vapi_ctx_instance);
- return rc;
-}
-
+};
diff --git a/src/plugins/ietf/ietf_interface.h b/src/plugins/ietf/ietf_interface.h
index 756f6ef..28a3783 100644
--- a/src/plugins/ietf/ietf_interface.h
+++ b/src/plugins/ietf/ietf_interface.h
@@ -16,43 +16,10 @@
#ifndef __IETF_INTERFACE_H__
#define __IETF_INTERFACE_H__
-#include "sc_vpp_comm.h"
+#include "../sc_model.h"
-#include <vapi/interface.api.vapi.h>
-
-typedef struct _s_vpp_interface_
-{
- u32 sw_if_index;
- char interface_name[VPP_INTFC_NAME_LEN];
- u8 l2_address[VPP_MAC_ADDRESS_LEN];
- u32 l2_address_length;
- u64 link_speed;
- u16 link_mtu;
- u8 admin_up_down;
- u8 link_up_down;
-}scVppIntfc;
-
-typedef struct _ietf_sw_interface_dump_ctx
-{
- u8 last_called;
- int num_ifs;
- int capacity;
- scVppIntfc * intfcArray;
-} ietf_sw_interface_dump_ctx;
-
-int ietf_initSwInterfaceDumpCTX(ietf_sw_interface_dump_ctx * dctx);
-int ietf_freeSwInterfaceDumpCTX(ietf_sw_interface_dump_ctx * dctx);
-int ietf_swInterfaceDump(ietf_sw_interface_dump_ctx * dctx);
-i32 ietf_interface_name2index(const char *name, u32* if_index);
-
-i32 ietf_interface_add_del_addr( u32 sw_if_index, u8 is_add, u8 is_ipv6, u8 del_all,
- u8 address_length, u8 address[VPP_IP6_ADDRESS_LEN] );
-i32 ietf_setInterfaceFlags(u32 sw_if_index, u8 admin_up_down);
-
-
-int
-ietf_interface_subscribe_events(sr_session_ctx_t *session,
- sr_subscription_ctx_t **subscription);
+#define IETF_INTERFACES_SIZE 5
+extern const xpath_t ietf_interfaces_xpaths[IETF_INTERFACES_SIZE];
#endif /* __IETF_INTERFACE_H__ */
diff --git a/src/plugins/openconfig/openconfig_interfaces.c b/src/plugins/openconfig/openconfig_interfaces.c
index e401e07..a1f66bb 100644
--- a/src/plugins/openconfig/openconfig_interfaces.c
+++ b/src/plugins/openconfig/openconfig_interfaces.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <sysrepo/xpath.h>
#include <sysrepo/values.h>
+#include <sysrepo.h>
#define XPATH_SIZE 2000
@@ -209,7 +210,7 @@ int openconfig_interface_mod_cb(
__attribute__((unused)) sr_notif_event_t event,
__attribute__((unused)) void *private_ctx)
{
- SRP_LOG_INF("Module subscribe: %s", module_name);
+ SRP_LOG_DBG("Interface module subscribe: %s", module_name);
return SR_ERR_OK;
}
@@ -876,3 +877,62 @@ int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_
return SR_ERR_OK;
}
+const xpath_t oc_interfaces_xpaths[OC_INTERFACES_SIZE] = {
+ {
+ .xpath = "openconfig-interfaces",
+ .method = MODULE,
+ .datastore = SR_DS_RUNNING,
+ .cb.mcb = openconfig_interface_mod_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ //.opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY
+ .opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY | SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-interfaces:interfaces/interface/config",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = openconfig_interfaces_interfaces_interface_config_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ //.opts = SR_SUBSCR_DEFAULT
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-interfaces:interfaces/interface/state",
+ .method = GETITEM,
+ .datastore = SR_DS_RUNNING,
+ .cb.gcb = openconfig_interfaces_interfaces_interface_state_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/state",
+ .method = GETITEM,
+ .datastore = SR_DS_RUNNING,
+ .cb.gcb = openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_state_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/openconfig-if-ip:addresses/openconfig-if-ip:address/openconfig-if-ip:config",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_config_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ //.opts = SR_SUBSCR_DEFAULT
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/openconfig-if-ip:addresses/openconfig-if-ip:address/openconfig-if-ip:state",
+ .method = GETITEM,
+ .datastore = SR_DS_RUNNING,
+ .cb.gcb = openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_state_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ .opts = SR_SUBSCR_CTX_REUSE
+ }
+};
diff --git a/src/plugins/openconfig/openconfig_interfaces.h b/src/plugins/openconfig/openconfig_interfaces.h
index df5e31c..88d5fe0 100644
--- a/src/plugins/openconfig/openconfig_interfaces.h
+++ b/src/plugins/openconfig/openconfig_interfaces.h
@@ -18,32 +18,9 @@
#ifndef __OPENCONFIG_INTERFACES_H__
#define __OPENCONFIG_INTERFACES_H__
-#include <sysrepo.h>
-
-int openconfig_interface_mod_cb(sr_session_ctx_t *session,
- const char *module_name,
- sr_notif_event_t event,
- void *private_ctx);
-
-int openconfig_interfaces_interfaces_interface_config_cb(
- sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event,
- void *private_ctx);
-
-int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_state_cb(
- const char *xpath, sr_val_t **values, size_t *values_cnt,
- uint64_t request_id, const char *original_xpath, void *private_ctx);
-
-int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_state_cb(
- const char *xpath, sr_val_t **values, size_t *values_cnt,
- uint64_t request_id, const char *original_xpath, void *private_ctx);
-
-int openconfig_interfaces_interfaces_interface_state_cb(
- const char *xpath, sr_val_t **values, size_t *values_cnt,
- uint64_t request_id, const char *original_xpath, void *private_ctx);
-
-int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_config_cb(
- sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event,
- void *private_ctx);
+#include "../sc_model.h"
+#define OC_INTERFACES_SIZE 6
+extern const xpath_t oc_interfaces_xpaths[OC_INTERFACES_SIZE];
#endif /* __OPENCONFIG_INTERFACES_H__ */
diff --git a/src/plugins/openconfig/openconfig_local_routing.c b/src/plugins/openconfig/openconfig_local_routing.c
index daf39cc..59574a2 100644
--- a/src/plugins/openconfig/openconfig_local_routing.c
+++ b/src/plugins/openconfig/openconfig_local_routing.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <string.h>
+#include <sysrepo.h>
#include <sysrepo/xpath.h>
#include <sysrepo/values.h>
@@ -728,3 +729,63 @@ int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_ho
return next_hop_inner(true, xpath, values, values_cnt, request_id,
private_ctx);
}
+
+const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE] = {
+ {
+ .xpath = "openconfig-local-routing",
+ .method = MODULE,
+ .datastore = SR_DS_RUNNING,
+ .cb.mcb = openconfig_local_routing_mod_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ //.opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY
+ .opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY | SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/config",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_config_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ //.opts = SR_SUBSCR_DEFAULT
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/interface-ref/config",
+ .method = XPATH,
+ .datastore = SR_DS_RUNNING,
+ .cb.scb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_config_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ //.opts = SR_SUBSCR_DEFAULT
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-local-routing:local-routes/static-routes/static/state",
+ .method = GETITEM,
+ .datastore = SR_DS_RUNNING,
+ .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_state_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/state",
+ .method = GETITEM,
+ .datastore = SR_DS_RUNNING,
+ .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_state_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+ {
+ .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/interface-ref/state",
+ .method = GETITEM,
+ .datastore = SR_DS_RUNNING,
+ .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_state_cb,
+ .private_ctx = NULL,
+ .priority = 0,
+ .opts = SR_SUBSCR_CTX_REUSE
+ },
+};
diff --git a/src/plugins/openconfig/openconfig_local_routing.h b/src/plugins/openconfig/openconfig_local_routing.h
index 4cd2966..13d2982 100644
--- a/src/plugins/openconfig/openconfig_local_routing.h
+++ b/src/plugins/openconfig/openconfig_local_routing.h
@@ -17,31 +17,9 @@
#ifndef __OPENCONFIG_LOCAL_ROUTING_H__
#define __OPENCONFIG_LOCAL_ROUTING_H__
-#include <sysrepo.h>
+#include "../sc_model.h"
-int openconfig_local_routing_mod_cb(sr_session_ctx_t *session,
- const char *module_name,
- sr_notif_event_t event,
- void *private_ctx);
-
-int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_config_cb(
- sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event,
- void *private_ctx);
-
-int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_config_cb(
- sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event,
- void *private_ctx);
-
-int openconfig_local_routing_local_routes_static_routes_static_state_cb(
- const char *xpath, sr_val_t **values, size_t *values_cnt,
- uint64_t request_id, const char *original_xpath, void *private_ctx);
-
-int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_state_cb(
- const char *xpath, sr_val_t **values, size_t *values_cnt,
- uint64_t request_id, const char *original_xpath, void *private_ctx);
-
-int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_state_cb(
- const char *xpath, sr_val_t **values, size_t *values_cnt,
- uint64_t request_id, const char *original_xpath, void *private_ctx);
+#define OC_LROUTING_SIZE 6
+extern const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE];
#endif /* __OPENCONFIG_LOCAL_ROUTING_H__ */
diff --git a/src/plugins/openconfig/openconfig_plugin.c b/src/plugins/openconfig/openconfig_plugin.c
deleted file mode 100644
index fbcd396..0000000
--- a/src/plugins/openconfig/openconfig_plugin.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (c) 2018 PANTHEON.tech.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "openconfig_plugin.h"
-#include "sys_util.h"
-#include "openconfig_interfaces.h"
-#include "openconfig_local_routing.h"
-#include "sc_vpp_comm.h"
-
-#include <assert.h>
-#include <string.h>
-#include <sysrepo/xpath.h>
-#include <sysrepo/values.h>
-
-#define XPATH_SIZE 2000
-
-static struct _sys_repo_call sysrepo_callback[] = {
- {
- .xpath = "openconfig-interfaces",
- .method = MODULE,
- .datastore = RUNNING,
- .cb.mcb = openconfig_interface_mod_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY
- },
- {
- .xpath = "openconfig-local-routing",
- .method = MODULE,
- .datastore = RUNNING,
- .cb.mcb = openconfig_local_routing_mod_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY
- },
- {
- .xpath = "/openconfig-interfaces:interfaces/interface/config",
- .method = XPATH,
- .datastore = RUNNING,
- .cb.scb = openconfig_interfaces_interfaces_interface_config_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_DEFAULT
- },
- {
- .xpath = "/openconfig-interfaces:interfaces/interface/state",
- .method = GETITEM,
- .datastore = RUNNING,
- .cb.gcb = openconfig_interfaces_interfaces_interface_state_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_CTX_REUSE
- },
- {
- .xpath = "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/state",
- .method = GETITEM,
- .datastore = RUNNING,
- .cb.gcb = openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_state_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_CTX_REUSE
- },
- {
- .xpath = "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/openconfig-if-ip:addresses/openconfig-if-ip:address/openconfig-if-ip:config",
- .method = XPATH,
- .datastore = RUNNING,
- .cb.scb = openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_config_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_DEFAULT
- },
- {
- .xpath = "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/openconfig-if-ip:addresses/openconfig-if-ip:address/openconfig-if-ip:state",
- .method = GETITEM,
- .datastore = RUNNING,
- .cb.gcb = openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_state_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_CTX_REUSE
- },
- {
- .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/config",
- .method = XPATH,
- .datastore = RUNNING,
- .cb.scb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_config_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_DEFAULT
- },
- {
- .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/interface-ref/config",
- .method = XPATH,
- .datastore = RUNNING,
- .cb.scb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_config_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_DEFAULT
- },
- {
- .xpath = "/openconfig-local-routing:local-routes/static-routes/static/state",
- .method = GETITEM,
- .datastore = RUNNING,
- .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_state_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_CTX_REUSE
- },
- {
- .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/state",
- .method = GETITEM,
- .datastore = RUNNING,
- .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_state_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_CTX_REUSE
- },
- {
- .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/interface-ref/state",
- .method = GETITEM,
- .datastore = RUNNING,
- .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_state_cb,
- .private_ctx = NULL,
- .priority = 0,
- .opts = SR_SUBSCR_CTX_REUSE
- },
-};
-
-static inline void
-append(plugin_subcscription_t **list, plugin_subcscription_t *new)
-{
- plugin_subcscription_t **tmp = list;
-
- while (*tmp)
- tmp = &(*tmp)->next;
-
- *tmp = new;
-}
-
-static int sys_repo_subscribe(plugin_main_t *plugin_main, sr_session_ctx_t *ds,
- struct _sys_repo_call *call)
-{
- plugin_subcscription_t *end, *new;
- int rc;
-
- new = calloc(sizeof(plugin_subcscription_t), 1);
- if (new == NULL)
- return SR_ERR_NOMEM;
- new->datastore = call->datastore;
-
- if (call->method == MODULE) {
- rc = sr_module_change_subscribe(ds, call->xpath, call->cb.mcb,
- call->private_ctx, call->priority,
- call->opts,
- &(new->sr_subscription_ctx));
- if (SR_ERR_OK != rc)
- goto error;
- } else if (call->method == XPATH) {
- rc = sr_subtree_change_subscribe(ds, call->xpath, call->cb.scb,
- call->private_ctx, call->priority,
- call->opts,
- &(new->sr_subscription_ctx));
- if (SR_ERR_OK != rc)
- goto error;
- } else if (call->method == GETITEM) {
- rc = sr_dp_get_items_subscribe(ds, call->xpath, call->cb.gcb,
- call->private_ctx, call->opts,
- &(new->sr_subscription_ctx));
- if (SR_ERR_OK != rc)
- goto error;
- } else if (call->method == RPC) {
- rc = sr_rpc_subscribe(ds, call->xpath, call->cb.rcb,
- call->private_ctx, call->opts,
- &(new->sr_subscription_ctx));
- if (SR_ERR_OK != rc)
- goto error;
- }
-
- SRP_LOG_DBG("Subscribed to xpath: %s", call->xpath);
-
- //add new subscription to the end of plugin subscription Linked List
- append(&(plugin_main->plugin_subcscription), new);
-
- return SR_ERR_OK;
-
-error:
- SRP_LOG_ERR("Error subscribed to RPC: %s", call->xpath);
- return rc;
-}
-
-int openconfig_register_subscribe(plugin_main_t* plugin_main)
-{
- int rc = 0;
- uint32_t i = 0;
- sr_session_ctx_t *datastore = NULL;
-
- ARG_CHECK(-1, plugin_main);
-
- for (i = 0; i < ARRAY_SIZE(sysrepo_callback); i++) {
- if (STARTUP == sysrepo_callback[i].datastore) {
- datastore = plugin_main->ds_startup;
- } else if (RUNNING == sysrepo_callback[i].datastore) {
- datastore = plugin_main->ds_running;
- } else {
- SRP_LOG_ERR_MSG("Error: wrong database type");
- return -1;
- }
-
- rc = sys_repo_subscribe(plugin_main, datastore, &sysrepo_callback[i]);
- if (SR_ERR_OK != rc) {
- SRP_LOG_ERR("Error: subscribing to subtree change, xpath: %s",
- sysrepo_callback[i].xpath);
-// return -1;
- }
- }
-
- return 0;
-}
-
-void openconfig_unsubscribe(plugin_main_t* plugin_main)
-{
- plugin_subcscription_t *plugin_subcscription, *tmp;
-
- if (plugin_main->plugin_subcscription == NULL)
- return;
-
- plugin_subcscription = plugin_main->plugin_subcscription;
- do {
- tmp = plugin_subcscription;
- plugin_subcscription = plugin_subcscription->next;
-
- if (tmp->datastore == STARTUP)
- sr_unsubscribe(plugin_main->ds_startup, tmp->sr_subscription_ctx);
- else if (tmp->datastore == RUNNING)
- sr_unsubscribe(plugin_main->ds_running, tmp->sr_subscription_ctx);
-
- free(tmp);
- } while (plugin_subcscription != NULL);
-}
-
-plugin_main_t plugin_main;
-
-int openconfig_plugin_init(sr_session_ctx_t* session)
-{
- memset((void*) &plugin_main, 0, sizeof(plugin_main));
-
- plugin_main.ds_running = session;
-
- openconfig_register_subscribe(&plugin_main);
-}
-
-void openconfig_plugin_cleanup()
-{
- openconfig_unsubscribe(&plugin_main);
-}
diff --git a/src/plugins/openconfig/openconfig_plugin.h b/src/plugins/openconfig/openconfig_plugin.h
deleted file mode 100644
index 714ae7d..0000000
--- a/src/plugins/openconfig/openconfig_plugin.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2018 PANTHEON.tech.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SWEETCOMB_OPENCONFIG_PLUGIN__
-#define __SWEETCOMB_OPENCONFIG_PLUGIN__
-
-#include <stdlib.h>
-#include <sysrepo.h>
-
-#define ARRAY_SIZE(X) (sizeof(X) / sizeof(*X))
-
-typedef enum {
- MODULE,
- XPATH,
- GETITEM,
- RPC,
-} method_e;
-
-typedef enum {
- STARTUP,
- RUNNING,
-} datastore_e;
-
-typedef struct _plugin_subcscription_t{
- datastore_e datastore;
- sr_subscription_ctx_t *sr_subscription_ctx;
- struct _plugin_subcscription_t *next;
-} plugin_subcscription_t;
-
-typedef struct {
- sr_conn_ctx_t *sr_conn_ctx;
- sr_session_ctx_t *ds_startup;
- sr_session_ctx_t *ds_running;
- //sr_session_ctx_t *ds_candidate;
- plugin_subcscription_t *plugin_subcscription;
-} plugin_main_t;
-
-struct _sys_repo_call {
- char *xpath;
- method_e method;
- datastore_e datastore;
- union {
- sr_module_change_cb mcb;
- sr_subtree_change_cb scb;
- sr_dp_get_items_cb gcb;
- sr_rpc_cb rcb;
- } cb;
- void *private_ctx;
- uint32_t priority;
- sr_subscr_options_t opts;
-};
-
-int openconfig_register_subscribe(plugin_main_t *plugin_main);
-void openconfig_unsubscribe(plugin_main_t *plugin_main);
-
-//FIXME:
-// This solution is not good and should be rewrite.
-// But first we must discuss the architecture of sweetcomb and how we should
-// register the new YANGS modules.
-// This function here is only for test.
-int openconfig_plugin_init(sr_session_ctx_t *session);
-void openconfig_plugin_cleanup();
-
-
-#endif /* __SWEETCOMB_OPENCONFIG_PLUGIN__ */
diff --git a/src/plugins/sc_model.c b/src/plugins/sc_model.c
new file mode 100644
index 0000000..d9bf92b
--- /dev/null
+++ b/src/plugins/sc_model.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 PANTHEON.tech.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sc_model.h"
+
+#include <sysrepo/plugins.h>
+
+static int
+subscribe(sr_session_ctx_t *ds, sr_subscription_ctx_t **sub,
+ const xpath_t *xpath)
+{
+ int rc;
+
+ switch (xpath->method) {
+ case MODULE:
+ rc = sr_module_change_subscribe(ds, xpath->xpath, xpath->cb.mcb,
+ xpath->private_ctx, xpath->priority,
+ xpath->opts, sub);
+ break;
+
+ case XPATH:
+ rc = sr_subtree_change_subscribe(ds, xpath->xpath, xpath->cb.scb,
+ xpath->private_ctx,
+ xpath->priority, xpath->opts, sub);
+ break;
+
+ case GETITEM:
+ rc = sr_dp_get_items_subscribe(ds, xpath->xpath, xpath->cb.gcb,
+ xpath->private_ctx, xpath->opts,
+ sub);
+ break;
+
+ case RPC:
+ rc = sr_rpc_subscribe(ds, xpath->xpath, xpath->cb.rcb,
+ xpath->private_ctx, xpath->opts, sub);
+ break;
+
+ default:
+ SRP_LOG_ERR("Unknown method %d", xpath->method);
+ return SR_ERR_NOT_FOUND;
+ }
+
+ if (SR_ERR_OK != rc) {
+ SRP_LOG_ERR("Error subscribing to %s", xpath->xpath);
+ return rc;
+ }
+
+ SRP_LOG_INF("Subscribed to xpath: %s", xpath->xpath);
+
+ return SR_ERR_OK;
+}
+
+int
+model_register(plugin_main_t* plugin_main, const xpath_t *xpaths, size_t size)
+{
+ int rc = 0;
+ uint32_t i = 0;
+
+ ARG_CHECK(-1, plugin_main);
+
+ for (i = 0; i < size; i++) {
+ rc = subscribe(plugin_main->session, &plugin_main->subscription,
+ &xpaths[i]);
+ if (SR_ERR_OK != rc)
+ SRP_LOG_ERR("Subscription failed for xpath: %s", xpaths[i].xpath);
+ }
+
+ return 0;
+}
diff --git a/src/plugins/sc_model.h b/src/plugins/sc_model.h
new file mode 100644
index 0000000..ec4bff4
--- /dev/null
+++ b/src/plugins/sc_model.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 PANTHEON.tech.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SC_MODEL_H__
+#define __SC_MODEL_H__
+
+/*
+ * IETF or Openconfig YANG models registering/unregistering
+ *
+ * Every model supports a certain number of operations which require a
+ * subscription to sysrepo : xpath_t
+ */
+
+#include <sysrepo.h>
+#include "sc_vpp_comm.h" //for ARG_CHECK only
+
+typedef enum {
+ MODULE,
+ XPATH,
+ GETITEM,
+ RPC,
+} method_e;
+
+#define ARRAY_SIZE(X) (sizeof(X) / sizeof(X[0]))
+
+typedef struct _xpath_t {
+ char *xpath;
+ method_e method;
+ sr_datastore_t datastore;
+ union {
+ sr_module_change_cb mcb;
+ sr_subtree_change_cb scb;
+ sr_dp_get_items_cb gcb;
+ sr_rpc_cb rcb;
+ } cb;
+ void *private_ctx;
+ uint32_t priority;
+ sr_subscr_options_t opts;
+} xpath_t;
+
+/*
+ * Stateful informations. Keep sesssions informations about a user
+ */
+
+typedef struct {
+ sr_session_ctx_t *session;
+ sr_subscription_ctx_t *subscription;
+} plugin_main_t;
+
+
+int
+model_register(plugin_main_t *plugin_main, const xpath_t *xpaths, size_t size);
+
+#endif /* __SC_MODEL_H__ */
diff --git a/src/plugins/sc_plugins.c b/src/plugins/sc_plugins.c
index 66790a1..e0db8ed 100644
--- a/src/plugins/sc_plugins.c
+++ b/src/plugins/sc_plugins.c
@@ -22,6 +22,8 @@
#include <vapi/vxlan.api.vapi.h>
#include <vnet/interface.h>
#include <vnet/mpls/mpls_types.h>
+
+// Use VAPI macros to define symbols
DEFINE_VAPI_MSG_IDS_VPE_API_JSON;
DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON;
DEFINE_VAPI_MSG_IDS_L2_API_JSON;
@@ -30,131 +32,51 @@ DEFINE_VAPI_MSG_IDS_TAPV2_API_JSON;
DEFINE_VAPI_MSG_IDS_IPSEC_API_JSON;
DEFINE_VAPI_MSG_IDS_VXLAN_API_JSON;
-
#include "sc_plugins.h"
+#include "sc_model.h"
+
#include "ietf/ietf_interface.h"
-#include "openconfig/openconfig_plugin.h"
+#include "openconfig/openconfig_interfaces.h"
+#include "openconfig/openconfig_local_routing.h"
int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx)
{
- SC_INVOKE_BEGIN;
- sr_subscription_ctx_t *subscription = NULL;
- int rc = SR_ERR_OK;
- rc = sc_connect_vpp();
- if (0 != rc)
- {
- SC_LOG_ERR("vpp connect error , with return %d.", rc);
- return SR_ERR_INTERNAL;
+ SC_INVOKE_BEGIN;
+ plugin_main_t plugin_main;
+ int rc;
+
+ rc = sc_connect_vpp();
+ if (0 != rc) {
+ SC_LOG_ERR("vpp connect error , with return %d.", rc);
+ return SR_ERR_INTERNAL;
}
- //SC_REGISTER_RPC_EVT_HANDLER(sc_ip_subscribe_route_events);
- //SC_REGISTER_RPC_EVT_HANDLER(sc_vxlan_subscribe_tunnel_events);
- //SC_REGISTER_RPC_EVT_HANDLER(sc_l2_bridge_domain_add_del_subscribe_events);
- //SC_REGISTER_RPC_EVT_HANDLER(sc_l2_interface_set_l2_bridge_subscribe_events);
+ plugin_main.session = session;
+ plugin_main.subscription = NULL;
+ /* Use the same sr_subscription_ctx for all models */
+ model_register(&plugin_main, ietf_interfaces_xpaths, IETF_INTERFACES_SIZE);
+ model_register(&plugin_main, oc_interfaces_xpaths, OC_INTERFACES_SIZE);
+ model_register(&plugin_main, oc_local_routing_xpaths, OC_LROUTING_SIZE);
- //INTERFACE
- ietf_interface_subscribe_events(session, &subscription);
+ /* set subscription as our private context */
+ *private_ctx = plugin_main.subscription;
+ SC_INVOKE_END;
- //Openconfig modules
- openconfig_plugin_init(session);
-
- /* set subscription as our private context */
- *private_ctx = subscription;
- SC_INVOKE_END;
- return SR_ERR_OK;
+ return SR_ERR_OK;
}
void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_ctx)
{
- SC_INVOKE_BEGIN;
+ SC_INVOKE_BEGIN;
- openconfig_plugin_cleanup();
+ /* subscription was set as our private context */
+ if (private_ctx != NULL)
+ sr_unsubscribe(session, private_ctx);
+ SC_LOG_DBG_MSG("unload plugin ok.");
- /* subscription was set as our private context */
- sr_unsubscribe(session, private_ctx);
- SC_LOG_DBG_MSG("unload plugin ok.");
- sc_disconnect_vpp();
- SC_LOG_DBG_MSG("plugin disconnect vpp ok.");
- SC_INVOKE_END;
-}
-
-
-///#############################
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <inttypes.h>
-sr_subscription_ctx_t *subscription = NULL;
-volatile int exit_application = 0;
-
-static void
-sigint_handler(int signum)
-{
- exit_application = 1;
+ sc_disconnect_vpp();
+ SC_LOG_DBG_MSG("plugin disconnect vpp ok.");
+ SC_INVOKE_END;
}
-int
-subscribe_all_module_events(sr_session_ctx_t *session)
-{
- sr_plugin_init_cb(session, (void**)&subscription);
- return 0;
-}
-int
-main(int argc, char **argv)
-{
- sr_conn_ctx_t *connection = NULL;
- sr_session_ctx_t *session = NULL;
- int rc = SR_ERR_OK;
-
- /* connect to vpp */
- rc = sc_connect_vpp();
- if (-1 == rc){
- fprintf(stderr, "vpp connect error");
- return -1;
- }
-
- /* connect to sysrepo */
- rc = sr_connect("cpe_application", SR_CONN_DEFAULT, &connection);
- if (SR_ERR_OK != rc) {
- fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc));
- goto cleanup;
- }
-
- /* start session */
- rc = sr_session_start(connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &session);
- if (SR_ERR_OK != rc) {
- fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc));
- goto cleanup;
- }
- /* subscribe all module events */
- rc = subscribe_all_module_events(session);
- if (SR_ERR_OK != rc) {
- fprintf(stderr, "Error by subscribe module events: %s\n", sr_strerror(rc));
- goto cleanup;
- }
-
- /* loop until ctrl-c is pressed / SIGINT is received */
- signal(SIGINT, sigint_handler);
- signal(SIGPIPE, SIG_IGN);
-
- while (!exit_application) {
- sleep(2);
- }
-
- printf("Application exit requested, exiting.\n");
-
- cleanup:
- if (NULL != subscription) {
- sr_unsubscribe(session, subscription);
- }
- if (NULL != session) {
- sr_session_stop(session);
- }
- if (NULL != connection) {
- sr_disconnect(connection);
- }
- sc_disconnect_vpp();
- return rc;
-}
diff --git a/src/plugins/sc_plugins.h b/src/plugins/sc_plugins.h
index 9e9f774..bdf88d7 100644
--- a/src/plugins/sc_plugins.h
+++ b/src/plugins/sc_plugins.h
@@ -25,7 +25,3 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx);
void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_ctx);
#endif //__SC_PLUGINS_H__
-
-
-
-