junos_app_init()
function in main()
after setting up the application context and any callbacks the application needs.Follow these steps to initialize your application on the Routing Engine:
junos_create_app_ctx()
first to create a context object.
junos_set_app_cb_xxx()
when necessary, to set up callbacks to be invoked during initialization. For the specific callback functions, see the SDK Library Reference documentation for the junos_init.h
file in libjunos-sdk.
SIGHUP
handler, and enable logging or the event loop for nondaemon applications. For the specific functions, see the SDK Library Reference documentation for the junos_init.h
file in libjunos-sdk.
junos_app_init()
to invoke the initialization process.
The code used to illustrate initialization on the Routing Engine is from the main()
function in the Route Manager sample application, available in /src/sbin/route-manager
in your sandbox. The main initialization code, which will be explained in the rest of this topic, is as follows:
int main (int argc, char **argv) { int rc = 0; junos_sdk_app_ctx_t app_ctx; const char *config_path[] = { "sync", "route-manager", NULL }; app_ctx = junos_create_app_ctx(argc, argv, "route-manager", NULL, PACKAGE_NAME, SEQUENCE_NUMBER); if (app_ctx == NULL) { return -1; } rc = junos_set_app_cb_config_read(app_ctx, config_read); if (rc < 0) { goto error; } rc = junos_set_app_cb_init(app_ctx, main_init); if (rc < 0) { goto error; } rc = junos_set_app_cfg_trace_path(app_ctx, config_path); if (rc < 0) { goto error; } rc = junos_app_init(app_ctx); error: /* should not come here unless daemon exiting or init failed, * destroy context */ junos_destroy_app_ctx(app_ctx); return rc; }
junos_sdk_app_ctx_t
and call junos_create_app_ctx()
, passing in various context parameters. These include the name of the daemon and the name of a commands menu if the application has one. This application does not have a commands menu, so it passes NULL
; for sample code that sets up a menu, see Creating a Commands Menu Array.
You also pass the constants PACKAGE_NAME
and SEQUENCE_NUMBER
; the defines for these are automatically generated by the DDL compiler that runs when you build your application, so you only need to reference the names in this call and include the appropriate header file as shown.
junos_set_app_cb_config_read()
specifies a function in the application that reads the application's configuration.
junos_set_app_cb_init()
specifies a function in the application that performs initialization activities specific to the application. For example, if the application needs to open sockets, register for routing socket notifications, and so forth, these tasks are done within this function.
junos_set_app_cfg_trace_path()
specifies the DDL path to the traceoptions configuration that the application should use to read configuration settings for the trace file. In this application, the DDL hierarchy is defined as follows in src/lib/ddl/input/route-manager/route-manager.cnf.dd
:
object sync { ... object route-manager { ... attribute routes { ... } object traceoptions { ... }
In the application code, the elements of the config_path
array specify the path from the root configuration node to the node containing the trace configuration node. The NULL indicates the end of the array. (When calling this function, do not call junos_trace_read_config()
from your configuration read callback. )
You can find additional initialization callback functions in the Library Reference documentation for junos_init.h
.
After these setup operations, you call junos_app_init()
to set the initialization actions in motion.
To initialize a nondaemon applications, you use the same function calls that you use to initialize a daemon, but some functionality is slightly different, as described next.
junos_app_init()
function to initialize a nondaemon utility, the following differences apply:
NULL
because these applications do not communicate with mgd over a socket.junos_set_app_cb_mastership_switch()
, must not be specified because these applications have no way to receive notification automatically. Thus, data replication is not supported for nondaemon applications.PACKAGE_NAME
and SEQUENCE_NUMBER
are required if the application needs to access a configuration database.sdk-common-include.dd
in your DDL *.cmd.dd
or *.cnf.dd
file to get the SDK-related definitions for nondaemon applications. The following DDL code snippet shows how to use the macro JUNOS_SDK_INSTALLDIR
to specify the path to a nondaemon SDK binary.
#include <sdk-common-include.dd> command juniper-command { command your_command { action execute spawn JUNOS_SDK_INSTALLDIR "/opt/sdk/your_binary" } }
junos_create_non_daemon_ctx()
function to create the application context, set the application type to non-daemon, and then set the appropriate flags to disable tracing, logging, and event context creation.
If instead your application needs tracing, logging, or events, you can call junos_create_app_ctx()
and then disable the flags you don't need (as shown in the following steps).
junos_create_app_ctx()
. This step creates the application context as a daemon context.
junos_app_type_non_daemon()
to set a bit in the flag field of the application context, indicating that this is a nondaemon context. This function must be the first function called after creating an application context.
junos_set_app_trace_enable()
to disable the trace flag in the application context.
junos_app_log_disable()
to disable the logging flag in the application context.
junos_app_disable_event_loop()
to disable the appropriate flag in the application context. An application can supply its own event context to libjunos-sdk by calling junos_set_app_event_ctx()
.
junos_set_app_cb_config_read()
to specify a callback function for reading the configurations. junos_app_init()
invokes the callback on initialization.
junos_set_app_cb_init()
to specify the functions.
junos_init.h
in libjunos-sdk.
junos_app_init()
to perform the initialization. msp_init()
function in the data daemon on the PIC, and the msp_app_init()
function in the control daemon on the PIC.Applications always have a component that runs on the Routing Engine as well as at least one component running on the PIC:
junos_app_init()
.msp_app_init()
function to initialize the application environment on the PIC, similarly to the function of junos_app_init()
on the Routing Engine.msp_init()
function to to match the current system capabilities, as well as any other required internal initialization. This function must be called before using any other Services SDK libraries.msp_init()
function without first rebooting the PIC. The attempt to invoke msp_init()
is checked at runtime, and an error is generated if the call was not at startup.
msp_create_app_ctx()
first to create a context object.create_event_loop
parameter to this function to specify whether the system should initially create an event loop.
msp_set_app_cb_init()
when necessary to set up callbacks to be invoked during initialization.
msp_sig_register()
to register a SIGHUP handler.
msp_set_app_cb_cmd_line_opts()
to handle options set from the command line.
msp_app_init()
to invoke the initialization process. Tracing is not set up by default; daemons on the PIC must use the trace functionality from libjuniper explicitly.
src/sbin/hellopics
) performs these intitializations:Management component on the Routing Engine:
int main (int argc, char ** argv) { const char * hp_config[] = {DDLNAME_SYNC, DDLNAME_SYNC_HELLOPICS, NULL}; int ret = 0; junos_sdk_app_ctx_t ctx; /* Create an application context */ ctx = junos_create_app_ctx(argc, argv, DNAME_HELLOPICS_MGMT, master_menu, PACKAGE_NAME, SEQUENCE_NUMBER); if (ctx == NULL) { return -1; } /* Set config read call back */ if ((ret = junos_set_app_cb_config_read(ctx, hellopics_config_read))) { goto cleanup; } /* Set init call back */ if ((ret = junos_set_app_cb_init(ctx, hellopics_init))) { goto cleanup; } /* set trace options DDL path */ ret = junos_set_app_cfg_trace_path(ctx, hp_config); if (ret < 0) { goto cleanup; } /* Calling junos_app_init */ ret = junos_app_init(ctx); cleanup: /* Destroying context if daemon init/exit failed */ junos_destroy_app_ctx(ctx); return ret; } static int hellopics_init (evContext ctx) { init_connection_stats(); return init_server(ctx); } status_t init_server(evContext ctx) { pconn_server_params_t params; ev_ctx = ctx; // init the sessions ctrl_session = NULL; data_session = NULL; // init module's other variables ctrl_ready = FALSE; data_ready = FALSE; received = TRUE; hello_seq_num = 0; evInitID(&timer_id); bzero(¶ms, sizeof(pconn_server_params_t)); // setup the server args params.pconn_port = HELLOPICS_PORT_NUM; params.pconn_max_connections = HELLOPICS_MGMT_SERVER_MAX_CONN; params.pconn_event_handler = receive_connection; // bind mgmt_server = pconn_server_create(¶ms, ctx, receive_message, NULL); if(mgmt_server == NULL) { ERRMSG(HELLOPICS_MGMT_LOG_TAG, TRACE_LOG_ERR, "%s: Failed to initialize the pconn server on port %d.", __FUNCTION__, HELLOPICS_PORT_NUM); return EFAIL; } junos_trace(HELLOPICS_TRACEFLAG_CONNECTION, "%s: Successfully initialized the pconn server on port %d.", __FUNCTION__, HELLOPICS_PORT_NUM); return SUCCESS; }
Control component on the PIC:
static int hellopics_ctrl_init (evContext ctx) { // Ignore some signals that we may receive: signal(SIGTERM, hellopics_ctrl_quit); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); logging_set_mode(LOGGING_SYSLOG); return init_connections(ctx); } status_t init_connections(evContext ctx) { pconn_server_params_t s_params; pconn_client_params_t c_params; // init the sessions data_session = NULL; // init the client in case it doesn't get init'd below mgmt_client = NULL; // init module's other variables data_ready = FALSE; mgmt_connected = FALSE; bzero(&s_params, sizeof(pconn_server_params_t)); // setup the server args s_params.pconn_port = HELLOPICS_PORT_NUM; s_params.pconn_max_connections = HELLOPICS_CTRL_SERVER_MAX_CONN; s_params.pconn_event_handler = receive_connection; // bind ctrl_server = pconn_server_create(&s_params, ctx, receive_message, NULL); if(ctrl_server == NULL) { LOG(LOG_ERR, "%s: Failed to initialize the pconn server on port %d.", __FUNCTION__, HELLOPICS_PORT_NUM); return EFAIL; } bzero(&c_params, sizeof(pconn_client_params_t)); // setup the client args c_params.pconn_peer_info.ppi_peer_type = PCONN_PEER_TYPE_RE; c_params.pconn_port = HELLOPICS_PORT_NUM; c_params.pconn_num_retries = MGMT_CLIENT_CONNECT_RETRIES; c_params.pconn_event_handler = client_connection; // connect mgmt_client = pconn_client_connect_async( &c_params, ctx, client_message, NULL); if(mgmt_client == NULL) { LOG(LOG_ERR, "%s: Failed to initialize the pconn client connection " "to the management component", __FUNCTION__); return EFAIL; } return SUCCESS; }
Data component on the PIC:
static int hellopics_data_init (evContext ctx) { msp_init(); // Handle some signals that we may receive: signal(SIGTERM, hellopics_data_quit); // call quit fnc signal(SIGHUP, SIG_IGN); // ignore signal(SIGPIPE, SIG_IGN); // ignore return init_connections(ctx); } status_t init_connections(evContext ctx) { pconn_client_params_t m_params; // init this client we connect later ctrl_client = NULL; ev_ctx = ctx; bzero(&m_params, sizeof(pconn_client_params_t)); // setup the client args m_params.pconn_peer_info.ppi_peer_type = PCONN_PEER_TYPE_RE; m_params.pconn_port = HELLOPICS_PORT_NUM; m_params.pconn_num_retries = MGMT_CLIENT_CONNECT_RETRIES; m_params.pconn_event_handler = mgmt_client_connection; // connect mgmt_client = pconn_client_connect_async( &m_params, ctx, mgmt_client_message, NULL); if(mgmt_client == NULL) { LOG(LOG_ERR, "%s: Failed to initialize the pconn client connection " "to the management component", __FUNCTION__); return EFAIL; } return SUCCESS; }
For additional details about the functionality in the HelloPics sample application, see Hello PICs: The Minimal Services SDK Application.