Пример #1
0
/*
 * 1. If any FAN failed, set all the other fans as full speed (100%)
 * 2. When (LM75-1 + LM75-2)/2 >= 49.5 C, set fan speed from 40% to 65%.
 * 3. When (LM75-1 + LM75-2)/2 >= 53C, set fan speed from 65% to 80%
 * 4. When (LM75-1 + LM75-2)/2 >= 57.7C, set fan speed from 80% to 100%

 * 5. When (LM75-1 + LM75-2)/2 <= 52.7C, set fan speed from 100% to 80%
 * 6. When (LM75-1 + LM75-2)/2 <= 47.7C, set fan speed from 80% to 65%
 * 7. When (LM75-1 + LM75-2)/2 <= 42.7C, set fan speed from 65% to 40%
 * 8. The default FAN speed is 40%
 */
int
onlp_sysi_platform_manage_fans(void)
{
#define LEV1_UP_TEMP    57500  /*temperature*/
#define LEV1_DOWN_TEMP  NULL  /* unused */
#define LEV1_SPEED_PERC 100   /*percentage*/

#define LEV2_UP_TEMP    53000
#define LEV2_DOWN_TEMP  52700
#define LEV2_SPEED_PERC 80

#define LEV3_UP_TEMP    49500
#define LEV3_DOWN_TEMP  47700
#define LEV3_SPEED_PERC 65

#define LEV4_UP_TEMP    NULL  /* unused */
#define LEV4_DOWN_TEMP  42700
#define LEV4_SPEED_PERC 40

#define FAN_NUM_ON_MAIN_BROAD  5


	int rc, i;
    int is_up;
    int new_temp, temp1, temp2, diff;
    static int new_perc = 0, ori_perc = 0;
    static int ori_temp = 0;
    onlp_thermal_info_t thermal_info;
    onlp_fan_info_t fan_info;

    /* get new temperature */
    if ((rc = onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(1), &thermal_info)) != ONLP_STATUS_OK)
        goto _EXIT;

    temp1 = thermal_info.mcelsius;

    if ((rc = onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(2), &thermal_info)) != ONLP_STATUS_OK)
        goto _EXIT;

    temp2 = thermal_info.mcelsius;

    new_temp = (temp1+temp2)/2;

    /* check fan status */
    for (i=1; i<=FAN_NUM_ON_MAIN_BROAD; i++)
    {
        if ((rc = onlp_fani_info_get(ONLP_FAN_ID_CREATE(i), &fan_info)) != ONLP_STATUS_OK)
            goto _EXIT;

        if (fan_info.status & ONLP_FAN_STATUS_FAILED)
        {
            new_perc = LEV1_SPEED_PERC;
            goto _CTRL;
        }
    }

    diff = new_temp - ori_temp;

    if (diff == 0)
        goto _EXIT;
    else
        is_up = (diff > 0 ? 1 : 0);

    if (is_up)
    {
        if (new_temp >= LEV1_UP_TEMP)
            new_perc = LEV1_SPEED_PERC;
        else if (new_temp >= LEV2_UP_TEMP)
            new_perc = LEV2_SPEED_PERC;
        else if (new_temp >= LEV3_UP_TEMP)
            new_perc = LEV3_SPEED_PERC;
        else
            new_perc = LEV4_SPEED_PERC;
    }
    else
    {
        if (new_temp <= LEV4_DOWN_TEMP)
            new_perc = LEV4_SPEED_PERC;
        else if (new_temp <= LEV3_DOWN_TEMP)
            new_perc = LEV3_SPEED_PERC;
        else if (new_temp <= LEV2_DOWN_TEMP)
            new_perc = LEV2_SPEED_PERC;
        else
            new_perc = LEV1_SPEED_PERC;
    }

_CTRL :

    if (LOCAL_DEBUG)
        printf("\n[DEBUG][%s][%d]{ori:temp=%d, perc=%d} {new:temp=%d, perc=%d}\n", __FUNCTION__, __LINE__,
                ori_temp, ori_perc, new_temp, new_perc);

    if (ori_perc == new_perc)
        goto _EXIT;

    /* ctrl fans */
    AIM_LOG_INFO("Fan Speeds are now at %d%%", new_perc);

    if ((rc = onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(1), new_perc)) != ONLP_STATUS_OK)
        goto _EXIT;

    /* update om */
    ori_perc = new_perc;
    ori_temp = new_temp;

_EXIT :

    return rc;
}
Пример #2
0
static void
client_callback(
    int socket_id,
    void *cookie,
    int read_ready,
    int write_ready,
    int error_seen)
{
    struct client *client = cookie;
    AIM_ASSERT(socket_id == client->fd);

    if (error_seen) {
        int socket_error = 0;
        socklen_t len = sizeof(socket_error);
        getsockopt(socket_id, SOL_SOCKET, SO_ERROR, &socket_error, &len);
        AIM_LOG_INFO("Error seen on CLI socket: %s", strerror(socket_error));
        destroy_client(client);
        return;
    }

    if (read_ready) {
        int c;
        if ((c = read(client->fd, client->read_buffer+client->read_buffer_offset,
                      READ_BUFFER_SIZE - client->read_buffer_offset)) < 0) {
            AIM_LOG_ERROR("read failed: %s", strerror(errno));
            return;
        }

        client->read_buffer_offset += c;

        if (c == 0) {
            /* Peer has shutdown their write side */
            if (client->write_buffer_len == 0 &&
                    aim_pvs_buffer_size(client->write_pvs) == 0) {
                destroy_client(client);
            } else {
                /* We'll destroy the client once we've finished writing to it */
                ind_soc_data_in_pause(client->fd);
                client->read_finished = true;
            }
            return;
        }

        /* Process each complete line */
        char *newline;
        char *start = client->read_buffer;
        int remaining = client->read_buffer_offset;
        while ((newline = memchr(start, '\n', remaining))) {
            *newline = '\0';
            ucli_dispatch_string(client->ucli, client->write_pvs, start);
            remaining -= newline - start + 1;
            start = newline + 1;
        }

        /* Move incomplete line (which may be empty) to the beginning of the read buffer */
        if (client->read_buffer != start) {
            memmove(client->read_buffer, start, remaining);
            client->read_buffer_offset = remaining;
        } else if (client->read_buffer_offset == READ_BUFFER_SIZE) {
            AIM_LOG_WARN("Disconnecting CLI client due to too-long line");
            destroy_client(client);
            return;
        }

        if (aim_pvs_buffer_size(client->write_pvs) > 0) {
            ind_soc_data_out_ready(socket_id);
        }
    }

    if (write_ready) {
        /* Copy PVS data into our write buffer and reset PVS */
        if (client->write_buffer == NULL) {
            client->write_buffer = aim_pvs_buffer_get(client->write_pvs);
            client->write_buffer_len = aim_pvs_buffer_size(client->write_pvs);
            client->write_buffer_offset = 0;
            /* aim_pvs_buffer_reset has a bug, workaround it */
            aim_pvs_destroy(client->write_pvs);
            client->write_pvs = aim_pvs_buffer_create();
        }

        int c = send(client->fd,
                     client->write_buffer+client->write_buffer_offset,
                     client->write_buffer_len-client->write_buffer_offset,
                     MSG_NOSIGNAL);
        if (c <= 0) {
            AIM_LOG_ERROR("write failed: %s", strerror(errno));
            destroy_client(client);
            return;
        }

        client->write_buffer_offset += c;

        /* Free our write buffer if we're finished with it */
        if (client->write_buffer_len == client->write_buffer_offset) {
            aim_free(client->write_buffer);
            client->write_buffer_len = client->write_buffer_offset = 0;
            client->write_buffer = NULL;
            if (aim_pvs_buffer_size(client->write_pvs) == 0) {
                ind_soc_data_out_clear(client->fd);
                if (client->read_finished) {
                    destroy_client(client);
                }
            }
        }
    }
}
Пример #3
0
/*
 * This function reads the SFPs idrom and returns in
 * in the data buffer provided.
 */
int
onlp_sfpi_eeprom_read(int port, uint8_t data[256])
{   
    int eeprombusidx, eeprombus, eeprombusbase;
    char eeprom_path[512], eeprom_addr[32];
    memset(eeprom_path, 0, sizeof(eeprom_path));    
    memset(eeprom_addr, 0, sizeof(eeprom_addr));    
    strncpy(eeprom_addr, "0050", sizeof(eeprom_addr));    
    
    memset(data, 0, 256);
    
    if (port >= 1 && port <= 8) {
        eeprombusbase=10;
    } else if (port >= 9 && port <= 16) {
        eeprombusbase=18;
    } else if (port >= 17 && port <= 24) {
        eeprombusbase=26;
    } else if (port >= 25 && port <= 32) {
        eeprombusbase=34;        
    } else {
        return 0;
    }
    
    eeprombusidx = port % 8;
    switch (eeprombusidx) {
        case 1:
            eeprombus = eeprombusbase + 1;
            break;
        case 2:
            eeprombus = eeprombusbase + 0;
            break;
        case 3:
            eeprombus = eeprombusbase + 3;
            break;
        case 4:
            eeprombus = eeprombusbase + 2;
            break;
        case 5:
            eeprombus = eeprombusbase + 5;
            break;
        case 6:
            eeprombus = eeprombusbase + 4;
            break;
        case 7:
            eeprombus = eeprombusbase + 7;
            break;
        case 0:
            eeprombus = eeprombusbase + 6;
            break;
        default:
            return ONLP_STATUS_E_INTERNAL;
            break;
    }
    
    snprintf(eeprom_path, sizeof(eeprom_path), 
             "/sys/bus/i2c/devices/%d-%s/eeprom", eeprombus, eeprom_addr);

    if (onlplib_sfp_eeprom_read_file(eeprom_path, data) != 0) {
        AIM_LOG_INFO("Unable to read eeprom from port(%d)\r\n", port);
        return ONLP_STATUS_E_INTERNAL;
    } 

    return ONLP_STATUS_OK;
}
Пример #4
0
int
aim_main(int argc, char* argv[])
{
    AIM_LOG_STRUCT_REGISTER();

    /*
     * We queue many (up to 20) 64KB messages before sending them on the socket
     * with a single writev(). After we free all the messages the malloc
     * implementation would see we have more than 128KB (the default trim value)
     * free and return it to the OS with a call to brk(). Every time we
     * allocate a new message we have to get the memory with brk() all over
     * again.
     *
     * Increasing the trim threshold above the size of our working set
     * eliminates this churn.
     */
    mallopt(M_TRIM_THRESHOLD, 2*1024*1024);

    loci_logger = ivs_loci_logger;

    core_cfg.expire_flows = 1;
    core_cfg.stats_check_ms = 900;
    core_cfg.disconnected_mode = INDIGO_CORE_DISCONNECTED_MODE_STICKY;

    parse_options(argc, argv);

    /* Setup logging from command line options */

    if (loglevel >= LOGLEVEL_DEFAULT) {
        aim_log_fid_set_all(AIM_LOG_FLAG_FATAL, 1);
        aim_log_fid_set_all(AIM_LOG_FLAG_ERROR, 1);
        aim_log_fid_set_all(AIM_LOG_FLAG_WARN, 1);
    }

    if (loglevel >= LOGLEVEL_VERBOSE) {
        aim_log_fid_set_all(AIM_LOG_FLAG_VERBOSE, 1);
    }

    if (loglevel >= LOGLEVEL_TRACE) {
        aim_log_fid_set_all(AIM_LOG_FLAG_TRACE, 1);
    }

    if (use_syslog) {
        aim_log_pvs_set_all(aim_pvs_syslog_open("ivs", LOG_NDELAY, LOG_DAEMON));
    }

    AIM_LOG_MSG("Starting %s (%s) pid %d", program_version, AIM_STRINGIFY(BUILD_ID), getpid());

    /* Initialize all modules */

    if (ind_soc_init(&soc_cfg) < 0) {
        AIM_LOG_FATAL("Failed to initialize Indigo socket manager");
        return 1;
    }

    if (ind_cxn_init(&cxn_cfg) < 0) {
        AIM_LOG_FATAL("Failed to initialize Indigo connection manager");
        return 1;
    }

    if (ind_core_init(&core_cfg) < 0) {
        AIM_LOG_FATAL("Failed to initialize Indigo core module");
        return 1;
    }

    if (ind_ovs_init(datapath_name, max_flows) < 0) {
        AIM_LOG_FATAL("Failed to initialize OVSDriver module");
        return 1;
    }

    if (lacpa_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize LACP Agent module");
        return 1;
    }

    if (lldpa_system_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize LLDP Agent module");
        return 1;
    }

    if (arpa_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize ARP Agent module");
        return 1;
    }

    if (router_ip_table_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize Router IP table module");
        return 1;
    }

    if (icmpa_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize ICMP Agent module");
        return 1;
    }

    if (dhcpra_system_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize DHCP relay table and agent module");
        return 1;
    }

    if (enable_tunnel) {
        if (ind_ovs_tunnel_init() < 0) {
            AIM_LOG_FATAL("Failed to initialize tunneling");
            return 1;
        }
    }

    if (pipeline == NULL) {
        if (openflow_version == NULL || !strcmp(openflow_version, "1.0")) {
            pipeline = "standard-1.0";
        } else if (!strcmp(openflow_version, "1.3")) {
            pipeline = "standard-1.3";
        } else {
            AIM_DIE("unexpected OpenFlow version");
        }
    }

    AIM_LOG_INFO("Initializing forwarding pipeline '%s'", pipeline);
    indigo_error_t rv = pipeline_set(pipeline);
    if (rv < 0) {
        AIM_LOG_FATAL("Failed to set pipeline: %s", indigo_strerror(rv));
        return 1;
    }

#if 0
    /* TODO Configuration module installs its own SIGHUP handler. */
    if (ind_cfg_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize Indigo configuration module");
        return 1;
    }
#endif

    if (config_filename) {
        ind_cfg_filename_set(config_filename);
        if (ind_cfg_load() < 0) {
            AIM_LOG_FATAL("Failed to load configuration file");
            return 1;
        }
    }

    if (dpid) {
        indigo_core_dpid_set(dpid);
    }

    /* Enable all modules */

    if (ind_soc_enable_set(1) < 0) {
        AIM_LOG_FATAL("Failed to enable Indigo socket manager");
        return 1;
    }

    if (ind_cxn_enable_set(1) < 0) {
        AIM_LOG_FATAL("Failed to enable Indigo connection manager");
        return 1;
    }

    if (ind_core_enable_set(1) < 0) {
        AIM_LOG_FATAL("Failed to enable Indigo core module");
        return 1;
    }

    /* Add interfaces from command line */
    {
        biglist_t *element;
        char *str;
        int index = 1;
        BIGLIST_FOREACH_DATA(element, interfaces, char *, str) {
            AIM_LOG_MSG("Adding interface %s (port %d)", str, index);
            if (indigo_port_interface_add(str, index, NULL)) {
                AIM_LOG_FATAL("Failed to add interface %s", str);
                return 1;
            }
            index++;
        }
    }
Пример #5
0
int
aim_main(int argc, char *argv[])
{
    set_crash_handler(crash_handler);

    AIM_LOG_STRUCT_REGISTER();

    loci_logger = ofagent_loci_logger;

    core_cfg.stats_check_ms = 900;

    parse_options(argc, argv);

    /* Setup logging from command line options */
    if (loglevel >= LOGLEVEL_DEFAULT) {
        aim_log_fid_set_all(AIM_LOG_FLAG_MSG, 1);
        aim_log_fid_set_all(AIM_LOG_FLAG_FATAL, 1);
        aim_log_fid_set_all(AIM_LOG_FLAG_ERROR, 1);
        aim_log_fid_set_all(AIM_LOG_FLAG_WARN, 1);
    }

    if (loglevel >= LOGLEVEL_VERBOSE) {
        aim_log_fid_set_all(AIM_LOG_FLAG_VERBOSE, 1);
    }

    if (loglevel >= LOGLEVEL_TRACE) {
        aim_log_fid_set_all(AIM_LOG_FLAG_TRACE, 1);
    }

    if (use_syslog) {
        aim_log_pvs_set_all(aim_pvs_syslog_open("ofagent", LOG_NDELAY, LOG_DAEMON));
    }

    create_pidfile();

    AIM_LOG_MSG("Starting ofagent %s (%s %s) pid %d",
            ofagent_version, ofagent_build_id, ofagent_build_os, getpid());

    /* Increase maximum number of file descriptors */
    struct rlimit rlim = {
        .rlim_cur = SOCKETMANAGER_CONFIG_MAX_SOCKETS,
        .rlim_max = SOCKETMANAGER_CONFIG_MAX_SOCKETS
    };
    if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
        AIM_LOG_WARN("Failed to increase RLIMIT_NOFILE");
    }

    /* Initialize all modules */
    if (ind_soc_init(&soc_cfg) < 0) {
        AIM_LOG_FATAL("Failed to initialize Indigo socket manager");
        return 1;
    }

    if (ind_cxn_init(&cxn_cfg) < 0) {
        AIM_LOG_FATAL("Failed to initialize Indigo connection manager");
        return 1;
    }

    if (ind_core_init(&core_cfg) < 0) {
        AIM_LOG_FATAL("Failed to initialize Indigo core module");
        return 1;
    }

    if (bcm_driver_init() < 0) {
        AIM_LOG_FATAL("Failed to initialize BCM driver");
        return 1;
    }

    if (pipeline == NULL) {
        if (openflow_version == NULL || !strcmp(openflow_version, "1.0")) {
            pipeline = "standard-1.0";
        } else if (!strcmp(openflow_version, "1.3")) {
            pipeline = "standard-1.3";
        } else {
            AIM_DIE("unexpected OpenFlow version");
        }
    }

    AIM_LOG_VERBOSE("Initializing forwarding pipeline '%s'", pipeline);
    indigo_error_t rv = pipeline_set(pipeline);
    if (rv < 0) {
        AIM_LOG_FATAL("Failed to set pipeline: %s", indigo_strerror(rv));
        return 1;
    }

    if (config_filename) {
        ind_cfg_filename_set(config_filename);
        if (ind_cfg_load() < 0) {
            AIM_LOG_FATAL("Failed to load configuration file");
            return 1;
        }
    }

    if (dpid) {
        indigo_core_dpid_set(dpid);
    }

    /* Enable all modules */
    if (ind_soc_enable_set(1) < 0) {
        AIM_LOG_FATAL("Failed to enable Indigo socket manager");
        return 1;
    }

    if (ind_cxn_enable_set(1) < 0) {
        AIM_LOG_FATAL("Failed to enable Indigo connection manager");
        return 1;
    }

    if (ind_core_enable_set(1) < 0) {
        AIM_LOG_FATAL("Failed to enable Indigo core module");
        return 1;
    }

    if (bcm_driver_enable_set(1) < 0) {
        AIM_LOG_FATAL("Failed to enable BCM driver");
        return 1;
    }

    /* Add controller from command line */
    {
        biglist_t *element;
        char *str;
        BIGLIST_FOREACH_DATA(element, controllers, char *, str) {
            AIM_LOG_VERBOSE("Adding controller %s", str);

            indigo_cxn_protocol_params_t proto;
            if (parse_controller(str, &proto, OF_TCP_PORT) < 0) {
                AIM_LOG_FATAL("Failed to parse controller string '%s'", str);
                return 1;
            }

            indigo_cxn_config_params_t config = {
                .version = OF_VERSION_1_0,
                .cxn_priority = 0,
                .local = 0,
                .listen = 0,
                .periodic_echo_ms = 2000,
                .reset_echo_count = 3,
            };

            indigo_controller_id_t id;
            if (indigo_controller_add(&proto, &config, &id) < 0) {
                AIM_LOG_FATAL("Failed to add controller %s", str);
                return 1;
            }
        }
    }

    ind_core_mfr_desc_set(mfr_desc);

    snprintf(sw_desc, sizeof(sw_desc),
            "ofagent %s %s %s", ofagent_version,
            ofagent_build_id, ofagent_build_os);
    ind_core_sw_desc_set(sw_desc);

    // TODO
    //read_hardware_version(hw_desc);
    ind_core_hw_desc_set(hw_desc);

    char hostname[256];
    char domainname[256];
    if (gethostname(hostname, sizeof(hostname))) {
        sprintf(hostname, "(unknown)");
    }
    if (getdomainname(domainname, sizeof(domainname))) {
        sprintf(domainname, "(unknown)");
    }
    snprintf(dp_desc, sizeof(dp_desc), "%s.%s pid %d",
             hostname, domainname, getpid());
    ind_core_dp_desc_set(dp_desc);

    AIM_LOG_INFO("Datapath description: %s", dp_desc);

    ind_core_serial_num_set(serial_num);

    /* The SIGHUP handler triggers sighup_callback to run in the main loop. */
    if ((sighup_eventfd = eventfd(0, 0)) < 0) {
        AIM_LOG_FATAL("Failed to allocate eventfd");
        abort();
    }
    signal(SIGHUP, sighup);
    if (ind_soc_socket_register(sighup_eventfd, sighup_callback, NULL) < 0) {
        abort();
    }

    /* The SIGTERM handler triggers sigterm_callback to run in the main loop. */
    if ((sigterm_eventfd = eventfd(0, 0)) < 0) {
        AIM_LOG_FATAL("Failed to allocate eventfd");
        abort();
    }
    signal(SIGTERM, sigterm);
    if (ind_soc_socket_register(sigterm_eventfd, sigterm_callback, NULL) < 0) {
        abort();
    }

    /* TODO Start handling upcalls */
    //ind_ovs_enable();

    //packet_trace_init(datapath_name);

    ind_soc_select_and_run(-1);

    AIM_LOG_MSG("Stopping ofagent %s", ofagent_version);

    ind_core_finish();
    bcm_driver_finish();
    ind_cxn_finish();
    ind_soc_finish();

    return 0;
}
static void
ind_cxn_cfg_commit(void)
{
    aim_log_t *lobj;
    int i, enable;

    if (staged_config.valid != true)
        return;

    /* Commit config only if connection manager is enabled. */
    (void) ind_cxn_enable_get(&enable);
    if (!enable)
        return;

    if ((lobj = aim_log_find("ofconnectionmanager")) == NULL) {
        AIM_LOG_WARN("Could not find log module");
    } else {
        lobj->common_flags = staged_config.log_flags;
    }

    /* configure TLS before parsing controller configs */
    (void) indigo_cxn_config_tls(staged_config.cipher_list,
                                 staged_config.ca_cert,
                                 staged_config.switch_cert,
                                 staged_config.switch_priv_key,
                                 staged_config.exp_controller_suffix);

    for (i = 0; i < staged_config.num_controllers; i++) {
        struct controller *c = &staged_config.controllers[i];
        const struct controller *old_controller;
        int rv;
        char desc[256];

        ind_cxn_proto_ip_string(&c->proto, desc, sizeof(desc));
        AIM_LOG_INFO("controller %d: %s", i, desc);

        /* Keep existing connections to the same controller. */
        if ((old_controller = find_controller(&current_config, &c->proto))) {
            c->controller_id = old_controller->controller_id;
            /* TODO apply keepalive_period to existing connection. */
            continue;
        }

        rv = indigo_controller_add(&c->proto, &c->config, &c->controller_id);
        if (rv != 0) {
            AIM_LOG_ERROR("failed to add controller connection %d: %s",
                          i, desc);
        }
    }

    /* Remove controller's that don't exist in the new configuration. */
    for (i = 0; i < current_config.num_controllers; i++) {
        const struct controller *c = &current_config.controllers[i];
        if (!find_controller(&staged_config, &c->proto)) {
            (void) indigo_controller_remove(c->controller_id);
        }
    }

    /* Save config so we can diff the controllers next time */
    current_config = staged_config;
    staged_config.valid = false;
}
static indigo_error_t
parse_tls_config(cJSON *root)
{
    indigo_error_t err;
    char *tls_mode;
    char *cipher_list;
    char *ca_cert;
    char *switch_cert;
    char *switch_priv_key;
    char *exp_controller_suffix;

    err = ind_cfg_lookup_string(root, "tls_mode", &tls_mode);
    if (err == INDIGO_ERROR_NOT_FOUND) {
        AIM_LOG_INFO("Config: TLS mode not set, defaulting to off");
        tls_mode = "off";
    } else if (err < 0) {
        if (err == INDIGO_ERROR_PARAM) {
            AIM_LOG_ERROR("Config: tls_mode must be a string");
        } else {
            AIM_LOG_ERROR("Config: %s", indigo_strerror(err));
        }
        goto error;
    }

    err = ind_cfg_lookup_string(root, "cipher_list", &cipher_list);
    if (err == INDIGO_ERROR_NOT_FOUND) {
        AIM_LOG_INFO("Config: No TLS cipher list, default to HIGH");
        cipher_list = "HIGH";
    } else if (err < 0) {
        if (err == INDIGO_ERROR_PARAM) {
            AIM_LOG_ERROR("Config: cipher_list must be a string");
        } else {
            AIM_LOG_ERROR("Config: %s", indigo_strerror(err));
        }
        goto error;
    }

    err = ind_cfg_lookup_string(root, "ca_cert", &ca_cert);
    if (err == INDIGO_ERROR_NOT_FOUND ||
        (ca_cert && ca_cert[0] == '\0')) {
        AIM_LOG_INFO("Config: No ca_cert given, allowing self-signed certs");
        ca_cert = NULL;
    } else if (err < 0) {
        if (err == INDIGO_ERROR_PARAM) {
            AIM_LOG_ERROR("Config: ca_cert must be a string");
        } else {
            AIM_LOG_ERROR("Config: %s", indigo_strerror(err));
        }
        goto error;
    }

    err = ind_cfg_lookup_string(root, "switch_cert", &switch_cert);
    if (err < 0) {
        if (err == INDIGO_ERROR_NOT_FOUND) {
            AIM_LOG_ERROR("Config: Missing switch_cert");
        } else if (err == INDIGO_ERROR_PARAM) {
            AIM_LOG_ERROR("Config: switch_cert must be a string");
        } else {
            AIM_LOG_ERROR("Config: %s", indigo_strerror(err));
        }
        goto error;
    }

    err = ind_cfg_lookup_string(root, "switch_priv_key", &switch_priv_key);
    if (err < 0) {
        if (err == INDIGO_ERROR_NOT_FOUND) {
            AIM_LOG_ERROR("Config: Missing switch_priv_key");
        } else if (err == INDIGO_ERROR_PARAM) {
            AIM_LOG_ERROR("Config: switch_priv_key must be a string");
        } else {
            AIM_LOG_ERROR("Config: %s", indigo_strerror(err));
        }
        goto error;
    }

    err = ind_cfg_lookup_string(root, "exp_controller_suffix",
                                &exp_controller_suffix);
    if (err == INDIGO_ERROR_NOT_FOUND ||
        (exp_controller_suffix && exp_controller_suffix[0] == '\0')) {
        AIM_LOG_INFO("Config: No exp_controller_suffix, "
                     "not verifying controller names");
        exp_controller_suffix = NULL;
    } else if (err < 0) {
        if (err == INDIGO_ERROR_PARAM) {
            AIM_LOG_ERROR("Config: exp_controller_suffix must be a string");
        } else {
            AIM_LOG_ERROR("Config: %s", indigo_strerror(err));
        }
        goto error;
    }

    if ((strcmp(tls_mode, "off") == 0) ||
        (strcmp(tls_mode, "optional") == 0)) {
        AIM_LOG_INFO("Config: tls_mode %s, ignoring ca_cert", tls_mode);
        ca_cert = NULL;
    } else if (strcmp(tls_mode, "strict") == 0) {
        AIM_LOG_INFO("Config: tls_mode %s, enforcing ca_cert", tls_mode);
    } else {
        AIM_LOG_ERROR("Config: bad tls_mode %s, aborting TLS config",
                      tls_mode);
        goto error;
    }

    if (ind_cxn_verify_tls(cipher_list, ca_cert,
                           switch_cert, switch_priv_key,
                           exp_controller_suffix) !=
        INDIGO_ERROR_NONE) {
        AIM_LOG_ERROR("Config: TLS parameter verification failed");
        goto error;
    }

    strncpy(staged_config.cipher_list, cipher_list, INDIGO_TLS_CFG_PARAM_LEN);
    if (ca_cert) {
        strncpy(staged_config.ca_cert, ca_cert, INDIGO_TLS_CFG_PARAM_LEN);
    } else {
        memset(staged_config.ca_cert, 0, INDIGO_TLS_CFG_PARAM_LEN);
    }
    strncpy(staged_config.switch_cert, switch_cert, INDIGO_TLS_CFG_PARAM_LEN);
    strncpy(staged_config.switch_priv_key, switch_priv_key,
            INDIGO_TLS_CFG_PARAM_LEN);
    if (exp_controller_suffix) {
        strncpy(staged_config.exp_controller_suffix, exp_controller_suffix,
                INDIGO_TLS_CFG_PARAM_LEN);
    } else {
        memset(staged_config.exp_controller_suffix, 0,
               INDIGO_TLS_CFG_PARAM_LEN);
    }

    AIM_LOG_INFO("Config: TLS mode %s, cipher list %s, ca_cert %s, "
                 "switch_cert %s, switch_priv_key %s, "
                 "exp_controller_suffix %s",
                 tls_mode, cipher_list, ca_cert? ca_cert: "NONE",
                 switch_cert, switch_priv_key,
                 exp_controller_suffix? exp_controller_suffix: "NONE");
    return INDIGO_ERROR_NONE;

 error:
    AIM_LOG_VERBOSE("Config: Clearing TLS params");
    memset(staged_config.cipher_list, 0, INDIGO_TLS_CFG_PARAM_LEN);
    memset(staged_config.ca_cert, 0, INDIGO_TLS_CFG_PARAM_LEN);
    memset(staged_config.switch_cert, 0, INDIGO_TLS_CFG_PARAM_LEN);
    memset(staged_config.switch_priv_key, 0, INDIGO_TLS_CFG_PARAM_LEN);
    memset(staged_config.exp_controller_suffix, 0, INDIGO_TLS_CFG_PARAM_LEN);
    return err;
}