コード例 #1
0
ファイル: cli.c プロジェクト: Juankc125/ivs
static void
listen_callback(
    int socket_id,
    void *cookie,
    int read_ready,
    int write_ready,
    int error_seen)
{
    AIM_LOG_TRACE("Accepting CLI client");

    int fd;
    if ((fd = accept(listen_socket, NULL, NULL)) < 0) {
        AIM_LOG_ERROR("Failed to accept on CLI socket: %s", strerror(errno));
        return;
    }

    struct client *client = aim_zmalloc(sizeof(*client));
    client->fd = fd;
    client->write_pvs = aim_pvs_buffer_create();
    client->ucli = ucli_create("ivs", NULL, NULL);

    indigo_error_t rv = ind_soc_socket_register(fd, client_callback, client);
    if (rv < 0) {
        AIM_LOG_ERROR("Failed to register CLI client socket: %s", indigo_strerror(rv));
        return;
    }
}
コード例 #2
0
ファイル: cli.c プロジェクト: Juankc125/ivs
void
ivs_cli_init(const char *path)
{
    ucli_init();

    unlink(path);

    listen_socket = socket(AF_UNIX, SOCK_STREAM, 0);
    if (listen_socket < 0) {
        perror("socket (CLI)");
        abort();
    }

    struct sockaddr_un saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.sun_family = AF_UNIX;
    strcpy(saddr.sun_path, path);

    if (bind(listen_socket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
        perror("bind (CLI)");
        abort();
    }

    if (listen(listen_socket, LISTEN_BACKLOG) < 0) {
        perror("listen (CLI)");
        abort();
    }

    indigo_error_t rv = ind_soc_socket_register(listen_socket, listen_callback, NULL);
    if (rv < 0) {
        AIM_DIE("Failed to register CLI socket: %s", indigo_strerror(rv));
    }
}
コード例 #3
0
ファイル: expiration.c プロジェクト: heecheolsong/indigo
static void
expire_flow(ft_entry_t *entry, int reason)
{
    if (reason == INDIGO_FLOW_REMOVED_HARD_TIMEOUT) {
        LOG_TRACE("Hard TO (%d): " INDIGO_FLOW_ID_PRINTF_FORMAT,
                  entry->hard_timeout,
                  INDIGO_FLOW_ID_PRINTF_ARG(entry->id));
        ind_core_flow_entry_delete(entry, reason, INDIGO_CXN_ID_UNSPECIFIED);
    } else if (reason == OF_FLOW_REMOVED_REASON_IDLE_TIMEOUT) {
        int rv;
        bool hit;

        /* Get hit status for idle timeouts */
        ind_core_table_t *table = ind_core_table_get(entry->table_id);
        if (table != NULL) {
            rv = table->ops->entry_hit_status_get(table->priv, INDIGO_CXN_ID_UNSPECIFIED,
                                                  entry->priv, &hit);
        } else {
            rv = indigo_fwd_flow_hit_status_get(entry->id, &hit);
        }

        if (rv != INDIGO_ERROR_NONE) {
            LOG_ERROR("Failed to get hit status for flow "
                      INDIGO_FLOW_ID_PRINTF_FORMAT": %s",
                      entry->id, indigo_strerror(rv));
            return;
        }

        if (hit || entry->flags & OF_FLOW_MOD_FLAG_BSN_SEND_IDLE) {
            /* Reinsert entry into the expiration list */
            entry->last_counter_change = INDIGO_CURRENT_TIME;
            ind_core_expiration_remove(entry);
            ind_core_expiration_add(entry);
        }

        if (!hit) {
            if (entry->flags & OF_FLOW_MOD_FLAG_BSN_SEND_IDLE) {
                send_idle_notification(entry);
            } else {
                LOG_TRACE("Idle TO (%d): " INDIGO_FLOW_ID_PRINTF_FORMAT,
                          entry->idle_timeout,
                          INDIGO_FLOW_ID_PRINTF_ARG(entry->id));
                ind_core_flow_entry_delete(entry, reason, INDIGO_CXN_ID_UNSPECIFIED);
            }
        }
    }
}
コード例 #4
0
ファイル: expiration.c プロジェクト: heecheolsong/indigo
void
ind_core_expiration_timer(void *cookie)
{
    int rv;
    (void) cookie;

    if (task_running) {
        AIM_LOG_VERBOSE("Not starting expiration task because it is already running");
        return;
    }

    if ((rv = ind_soc_task_register(expiration_task, NULL,
                                    IND_SOC_NORMAL_PRIORITY)) < 0) {
        AIM_LOG_ERROR("Failed to start flow expiration task: %s",
                      indigo_strerror(rv));
    } else {
        task_running = true;
    }
}
コード例 #5
0
void
ind_core_bsn_table_set_buckets_size_handler(of_object_t *_obj,
                                            indigo_cxn_id_t cxn_id)
{
    of_bsn_table_set_buckets_size_t *obj = _obj;
    uint16_t table_id;
    uint32_t buckets_size;
    indigo_error_t rv;

    of_bsn_table_set_buckets_size_table_id_get(obj, &table_id);
    of_bsn_table_set_buckets_size_buckets_size_get(obj, &buckets_size);

    rv = ft_set_checksum_buckets_size(ind_core_ft, table_id, buckets_size);
    if (rv < 0) {
        AIM_LOG_WARN("Failed to set table %d checksum buckets size to %d: %s",
                     table_id, buckets_size, indigo_strerror(rv));
        indigo_cxn_send_error_reply(cxn_id, obj,
                                    OF_ERROR_TYPE_BAD_REQUEST,
                                    OF_REQUEST_FAILED_EPERM);
    }
}
コード例 #6
0
indigo_error_t
ind_cxn_cfg_stage(cJSON *config)
{
    indigo_error_t err;

    err = ind_cfg_parse_loglevel(config, "logging.connection",
                                 OFCONNECTIONMANAGER_CONFIG_LOG_BITS_DEFAULT,
                                 &staged_config.log_flags);
    if (err != INDIGO_ERROR_NONE) {
        return err;
    }

    /* Not supporting setting log options yet */

    err = ind_cfg_lookup_int(config, "keepalive_period_ms", &staged_config.keepalive_period_ms);
    if (err == INDIGO_ERROR_NONE) {
        if (staged_config.keepalive_period_ms <= 0) {
            AIM_LOG_ERROR("'keepalive_period_ms' must be greater than 0");
            return INDIGO_ERROR_PARAM;
        }
    } else if (err == INDIGO_ERROR_PARAM) {
        AIM_LOG_ERROR("Config: Could not parse 'keepalive_period_ms'");
        return err;
    } else if (err == INDIGO_ERROR_NOT_FOUND) {
        AIM_LOG_ERROR("Config: Missing required key 'keepalive_period_ms'");
        return err;
    }

    err = parse_controllers(config);
    if (err != INDIGO_ERROR_NONE) {
        return err;
    }

    /* verify TLS parameters */
    /*
     * for now, we should be able to accept:
     * - TLS config with switch cert and key specified,
     *   cipher_list and CA cert optional
     * - if cipher_list is specified, it should be valid
     * - if CA cert is specified, it should be consistent with switch cert
     * - TLS config with parameters specified, but
     *   CA cert, switch cert and switch priv key files not present
     */
    {
        cJSON *node = cJSON_GetObjectItem(config, "tls");
        if (node) {
            if (node->type != cJSON_Object) {
                AIM_LOG_ERROR("Config: expected tls to be an object");
                return INDIGO_ERROR_PARAM;
            }
            err = parse_tls_config(node);
            if (err != INDIGO_ERROR_NONE) {
                AIM_LOG_ERROR("Config: error parsing TLS config: %s",
                              indigo_strerror(err));
                return err;
            }
        } else {
            AIM_LOG_VERBOSE("Config: TLS config not found, continuing");
        }
    }

    staged_config.valid = true;

    return INDIGO_ERROR_NONE;
}
コード例 #7
0
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;
    }

#if OFCONNECTIONMANAGER_CONFIG_FIPS == 0
    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;
    }
#else
    AIM_LOG_INFO("Config: overriding TLS cipher list with %s",
                 OFCONNECTIONMANAGER_CONFIG_FIPS_CIPHER_LIST);
    cipher_list = OFCONNECTIONMANAGER_CONFIG_FIPS_CIPHER_LIST;
#endif

    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;
}
コード例 #8
0
ファイル: main.c プロジェクト: kwang-bsn/ivs
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++;
        }
    }
コード例 #9
0
ファイル: main.c プロジェクト: JunhoSuh/ofagent
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;
}