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; } }
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)); } }
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); } } } }
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; } }
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); } }
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; }
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; }
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++; } }
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; }