Initializing an Application

There are three different contexts in which you initialize applications:

Initializing a Daemon on the Routing Engine

To initialize itself on the Routing Engine, an application calls the 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:

  1. Call junos_create_app_ctx() first to create a context object.

  2. Call 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.

  3. Optionally, call additional functions to set the trace options configuration path, register a 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.

  4. Finally, call 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;
}

The Packet Context

You declare a context pointer using the built-in SDK type 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.

Specifying Callbacks

The application can make callbacks upon initialization by specifying additional initialization functions. The sample code makes these calls:

Initializing a Nondaemon Application on the Routing Engine

For introductory information about nondaemon applications (utilities), see Non Daemon Applications. For a sample program, see the data component of the ip-probe example: The IP Probe Application.

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.

Using junos_app_init() with Nondaemon Applications

When you call the junos_app_init() function to initialize a nondaemon utility, the following differences apply:

DDL for Nondaemon Applications

You can include 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"
    }
}

Functionality Not Needed

The following functionality is not needed for nondaemons:

Tracing, Logging, and Events

Tracing, logging and event context can be used if needed in the utility. Because these are usually not needed, you can call the 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).

Initialization Steps

Follow these steps to initialize a nondaemon application:

  1. Create an application context using junos_create_app_ctx(). This step creates the application context as a daemon context.

  2. Call 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.

  3. If the application will not require tracing, call junos_set_app_trace_enable() to disable the trace flag in the application context.

  4. If the application will not require the syslog, call junos_app_log_disable() to disable the logging flag in the application context.

  5. If the application will not require the event context, call 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().

  6. If the application will need to read the configuration database, call junos_set_app_cb_config_read() to specify a callback function for reading the configurations. junos_app_init() invokes the callback on initialization.

  7. If the application will need to perform specific functions such as opening sockets, creating timers, and so forth, call junos_set_app_cb_init() to specify the functions.

  8. Call additional setup functions as needed. For details, see the Library Reference for junos_init.h in libjunos-sdk.

  9. Call junos_app_init() to perform the initialization.

Initializing a Daemon on the Multiservices PIC

To initialize a daemon on the Multiservices PIC, you call the 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:

Note:
The Services SDK does not support restarts for data daemons. Multiservices PIC initialization is performed only once, at startup. If your application fails, you must reboot the Multiservices PIC. It is not possible to reinitialize the Multiservices PIC by invoking the 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.

Initialization Steps on the PIC

The steps you follow on the Multiservices PIC are similar to those on the Routing Engine, omitting some functionality (such as the config read and mastership switch callbacks) that only occurs on the Routing Engine, and adding other functionality (such as allowing you to specify whether to create an event loop) that is specific to the PIC. A summary is as follows:

  1. Call msp_create_app_ctx() first to create a context object.

    On the PIC, you set the create_event_loop parameter to this function to specify whether the system should initially create an event loop.

  2. Call msp_set_app_cb_init() when necessary to set up callbacks to be invoked during initialization.

  3. Optionally, call msp_sig_register() to register a SIGHUP handler.

  4. Optionally, call msp_set_app_cb_cmd_line_opts() to handle options set from the command line.

  5. Call 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.

Multiservices PIC Initialization Example

For example, the HelloPics sample application (in your development sandbox at 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(&params, 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(&params, 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.


2007-2009 Juniper Networks, Inc. All rights reserved. The information contained herein is confidential information of Juniper Networks, Inc., and may not be used, disclosed, distributed, modified, or copied without the prior written consent of Juniper Networks, Inc. in an express license. This information is subject to change by Juniper Networks, Inc. Juniper Networks, the Juniper Networks logo, and JUNOS are registered trademarks of Juniper Networks, Inc. in the United States and other countries. All other trademarks, service marks, registered trademarks, or registered service marks are the property of their respective owners.
Generated on Sun May 30 20:26:47 2010 for Juniper Networks Partner Solution Development Platform JUNOS SDK 10.2R1 by Doxygen 1.4.5