void test_list(void) { struct histogram *hist1 = histogram_create("hist1"); struct histogram *hist2 = histogram_create("hist2"); struct histogram *hist3 = aim_zmalloc(sizeof(*hist3)); histogram_register(hist3, "hist3"); AIM_ASSERT(!strcmp(hist1->name, "hist1")); AIM_ASSERT(!strcmp(hist2->name, "hist2")); AIM_ASSERT(!strcmp(hist3->name, "hist3")); struct list_head *head = histogram_list(); struct list_links *cur = list_first(head); AIM_ASSERT(container_of(cur, links, struct histogram) == hist1); cur = cur->next; AIM_ASSERT(container_of(cur, links, struct histogram) == hist2); cur = cur->next; AIM_ASSERT(container_of(cur, links, struct histogram) == hist3); AIM_ASSERT(cur->next == &head->links); histogram_destroy(hist1); histogram_destroy(hist2); histogram_unregister(hist3); aim_free(hist3); }
void debug_counter_register(debug_counter_t *counter, const char *name, const char *description) { counter->value = 0; counter->counter_id = debug_counter_next_id++; list_push(&debug_counters, &counter->links); AIM_ASSERT(strlen(name) > 0 && strlen(name) < DEBUG_COUNTER_NAME_SIZE); counter->name = name; AIM_ASSERT(strlen(description) > 0 && strlen(description) < DEBUG_COUNTER_DESCRIPTION_SIZE); counter->description = description; debug_counter_inc(®ister_counter); }
static void check(struct histogram *hist, uint32_t k, uint32_t v) { uint32_t i = histogram_bucket(k); AIM_ASSERT(i < HISTOGRAM_BUCKETS); uint32_t v2 = hist->counts[i]; if (v != v2) { AIM_DIE("Expected %u at key %u (index %u), found %u", v, k, i, v2); } }
static void test_autogrow(void) { { bighash_table_t *table = bighash_table_create(BIGHASH_AUTOGROW); biglist_t *entries = NULL; insert__(table, 63, &entries); AIM_ASSERT(table->bucket_count == 128); test_table_data__(table, &entries); bighash_table_destroy(table, NULL); } { bighash_table_t *table = bighash_table_create(BIGHASH_AUTOGROW); biglist_t *entries = NULL; insert__(table, 64, &entries); AIM_ASSERT(table->bucket_count == 256); test_table_data__(table, &entries); bighash_table_destroy(table, NULL); } }
/* * Using random tcam entries and lookup keys (but unique priorities), compare * the tcam to a reference implementation. */ static void test_random(void) { const int num_entries = 10000; const int num_lookups = 10000; const int num_masks = 128; struct tcam *tcam = tcam_create(sizeof(struct tcam_key), 42); struct tcam_entry *es = calloc(num_entries, sizeof(*es)); assert(es); int i; struct tcam_key key, mask; /* Add entries */ for (i = 0; i < num_entries; i++) { uint64_t mask_pattern = rand() % num_masks; key = make_key(rand() & mask_pattern); mask = make_key(mask_pattern); tcam_insert(tcam, &es[i], &key, &mask, i); assert(tcam_match(tcam, &key) == &es[i]); } /* Random lookups */ for (i = 0; i < num_lookups; i++) { key = make_key(rand()); struct tcam_entry *tcam_result = tcam_match(tcam, &key); /* Linear search to find highest priority match */ int j; struct tcam_entry *ref_result = NULL; for (j = num_entries-1; j >= 0; j--) { uint64_t key_pattern = ((struct tcam_key *)es[j].key)->data[0]; uint64_t mask_pattern = ((struct tcam_key *)es[j].mask)->data[0]; if ((key.data[0] & mask_pattern) == key_pattern) { ref_result = &es[j]; break; } } AIM_ASSERT(tcam_result == ref_result, "mismatch with reference"); } /* Remove entries */ for (i = 0; i < num_entries; i++) { tcam_remove(tcam, &es[i]); } tcam_destroy(tcam); free(es); }
void test_find(void) { AIM_ASSERT(histogram_find("hist1") == NULL); AIM_ASSERT(histogram_find("hist2") == NULL); struct histogram *hist1 = histogram_create("hist1"); AIM_ASSERT(histogram_find("hist1") == hist1); AIM_ASSERT(histogram_find("hist2") == NULL); struct histogram *hist2 = histogram_create("hist2"); AIM_ASSERT(histogram_find("hist1") == hist1); AIM_ASSERT(histogram_find("hist2") == hist2); histogram_destroy(hist1); AIM_ASSERT(histogram_find("hist1") == NULL); AIM_ASSERT(histogram_find("hist2") == hist2); histogram_destroy(hist2); AIM_ASSERT(histogram_find("hist1") == NULL); AIM_ASSERT(histogram_find("hist2") == NULL); }
static void handle_lua_upload(indigo_cxn_id_t cxn_id, of_object_t *msg) { of_octets_t data; uint16_t flags; of_str64_t filename; of_bsn_lua_upload_data_get(msg, &data); of_bsn_lua_upload_flags_get(msg, &flags); of_bsn_lua_upload_filename_get(msg, &filename); /* Ensure filename is null terminated */ filename[63] = 0; if (xbuf_length(&upload_chunks) + sizeof(struct upload_chunk) + data.bytes > MAX_UPLOAD_SIZE) { AIM_LOG_ERROR("Attempted to upload more than %u bytes", MAX_UPLOAD_SIZE); indigo_cxn_send_error_reply( cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM); cleanup_lua_upload(); return; } /* If the list isn't empty, get a pointer to the last uploaded chunk */ struct upload_chunk *prev = NULL; if (xbuf_length(&upload_chunks) > 0) { AIM_ASSERT(last_uploaded_chunk_offset < xbuf_length(&upload_chunks)); prev = xbuf_data(&upload_chunks) + last_uploaded_chunk_offset; } if (prev && !memcmp(filename, prev->filename, sizeof(filename))) { /* Concatenate consecutive messages with the same filename */ prev->size += data.bytes; xbuf_append(&upload_chunks, (char *)data.data, data.bytes); AIM_LOG_VERBOSE("Appended to Lua chunk %s, now %u bytes", prev->filename, prev->size); } else if (data.bytes > 0) { last_uploaded_chunk_offset = xbuf_length(&upload_chunks); struct upload_chunk *chunk = xbuf_reserve(&upload_chunks, sizeof(*chunk) + data.bytes); chunk->size = data.bytes; memcpy(chunk->filename, filename, sizeof(of_str64_t)); memcpy(chunk->data, data.data, data.bytes); AIM_LOG_VERBOSE("Uploaded Lua chunk %s, %u bytes", chunk->filename, chunk->size); } if (!(flags & OFP_BSN_LUA_UPLOAD_MORE)) { commit_lua_upload(cxn_id, msg); } }
void test_bucket(void) { struct { uint32_t k; uint32_t bucket; uint32_t reverse; } tests[] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, { 14, 14, 14 }, { 15, 15, 15 }, { 16, 16, 16 }, { 17, 17, 17 }, { 30, 30, 30 }, { 31, 31, 31 }, { 32, 32, 32 }, { 33, 32, 32 }, { 34, 33, 34 }, { 62, 47, 62 }, { 63, 47, 62 }, { 64, 48, 64 }, { 65, 48, 64 }, { 66, 48, 64 }, { 67, 48, 64 }, { 68, 49, 68 }, { UINT32_MAX, 463, 4160749568 }, }; int i; for (i = 0; i < AIM_ARRAYSIZE(tests); i++) { uint32_t actual = histogram_bucket(tests[i].k); if (tests[i].bucket != actual) { AIM_DIE("histogram_bucket test failed: k=%u expect=%u actual=%u", tests[i].k, tests[i].bucket, actual); } AIM_ASSERT(tests[i].bucket == histogram_bucket(tests[i].reverse)); actual = histogram_key(tests[i].bucket); if (tests[i].reverse != actual) { AIM_DIE("histogram_key test failed: bucket=%u expect=%u actual=%u", tests[i].bucket, tests[i].reverse, actual); } } }
static void bighash_grow(bighash_table_t *table) { AIM_ASSERT(aim_is_pow2_u32(table->bucket_count), "Bucket count must be a power of 2"); int new_bucket_count = table->bucket_count * 2; bighash_entry_t **new_buckets = aim_malloc(sizeof(new_buckets[0]) * new_bucket_count); /* Bit that decides whether we go in the hi or lo bucket */ uint32_t bit = table->bucket_count; int i; for (i = 0; i < table->bucket_count; i++) { bighash_entry_t *cur = table->buckets[i]; bighash_entry_t **new_tail_lo = &new_buckets[i]; bighash_entry_t **new_tail_hi = &new_buckets[bit + i]; /* Initialize new buckets to an empty list */ *new_tail_lo = NULL; *new_tail_hi = NULL; while (cur != NULL) { /* Get the new tail */ bighash_entry_t ***new_tail_ptr = cur->hash & bit ? &new_tail_hi : &new_tail_lo; bighash_entry_t **new_tail = *new_tail_ptr; bighash_entry_t *next = cur->next; /* Add cur to the end of the list */ *new_tail = cur; cur->next = NULL; /* Advance local list pointers */ *new_tail_ptr = &cur->next; cur = next; } } aim_free(table->buckets); table->bucket_count = new_bucket_count; table->buckets = new_buckets; }
static int compare_message(const void *_a, const void *_b) { AIM_ASSERT(comparator != NULL); of_object_storage_t obj_a_storage; of_object_t *obj_a = parse_message(*(uint8_t * const *)_a, &obj_a_storage); of_object_storage_t obj_b_storage; of_object_t *obj_b = parse_message(*(uint8_t * const *)_b, &obj_b_storage); if (obj_a == NULL || obj_b == NULL) { return 0; } if (obj_a->object_id == OF_BARRIER_REQUEST) { /* Barriers go to the end of the bundle */ return 1; } return comparator(obj_a, obj_b); }
/* * icmp_send_packet_out * * Send the ICMP message out */ indigo_error_t icmpa_send_packet_out (of_octets_t *octets) { of_packet_out_t *obj; of_list_action_t *list; of_action_output_t *action; indigo_error_t rv; if (!octets) return INDIGO_ERROR_PARAM; obj = of_packet_out_new(OF_VERSION_1_3); AIM_TRUE_OR_DIE(obj != NULL); list = of_list_action_new(OF_VERSION_1_3); AIM_TRUE_OR_DIE(list != NULL); action = of_action_output_new(OF_VERSION_1_3); AIM_TRUE_OR_DIE(action != NULL); of_packet_out_buffer_id_set(obj, -1); of_packet_out_in_port_set(obj, OF_PORT_DEST_CONTROLLER); of_action_output_port_set(action, OF_PORT_DEST_USE_TABLE); of_list_append(list, action); of_object_delete(action); rv = of_packet_out_actions_set(obj, list); AIM_ASSERT(rv == 0); of_object_delete(list); rv = of_packet_out_data_set(obj, octets); if (rv < 0) { AIM_LOG_ERROR("ICMPA: Failed to set data on packet out"); of_packet_out_delete(obj); return rv; } rv = indigo_fwd_packet_out(obj); of_packet_out_delete(obj); return rv; }
static void reset_lua(void) { if (lua) { pipeline_lua_table_reset(); pipeline_lua_stats_reset(); lua_close(lua); } lua = luaL_newstate(); if (lua == NULL) { AIM_DIE("failed to allocate Lua state"); } luaL_openlibs(lua); /* Give Lua a pointer to the static context struct */ context.valid = false; lua_pushlightuserdata(lua, &context); lua_setglobal(lua, "_context"); /* Give Lua the names of all fields */ lua_newtable(lua); int i = 0; while (pipeline_lua_field_names[i]) { lua_pushstring(lua, pipeline_lua_field_names[i]); lua_rawseti(lua, -2, i+1); i++; } lua_setglobal(lua, "field_names"); lua_pushcfunction(lua, pipeline_lua_table_register); lua_setglobal(lua, "register_table"); const struct builtin_lua *builtin_lua; for (builtin_lua = &pipeline_lua_builtin_lua[0]; builtin_lua->name; builtin_lua++) { AIM_LOG_VERBOSE("Loading builtin Lua code %s", builtin_lua->name); char name[64]; snprintf(name, sizeof(name), "=%s", builtin_lua->name); /* Parse */ if (luaL_loadbuffer(lua, builtin_lua->start, builtin_lua->end-builtin_lua->start, name) != 0) { AIM_DIE("Failed to load built-in Lua code %s: %s", builtin_lua->name, lua_tostring(lua, -1)); } /* Execute */ if (lua_pcall(lua, 0, 0, 0) != 0) { AIM_DIE("Failed to execute built-in Lua code %s: %s", builtin_lua->name, lua_tostring(lua, -1)); } } /* Store a reference to process() so we can efficiently retrieve it */ lua_getglobal(lua, "process"); AIM_ASSERT(lua_isfunction(lua, -1)); process_ref = luaL_ref(lua, LUA_REGISTRYINDEX); /* Store a reference to command() so we can efficiently retrieve it */ lua_getglobal(lua, "command"); AIM_ASSERT(lua_isfunction(lua, -1)); command_ref = luaL_ref(lua, LUA_REGISTRYINDEX); /* Store a reference to pktin() so we can efficiently retrieve it */ lua_getglobal(lua, "pktin"); AIM_ASSERT(lua_isfunction(lua, -1)); pktin_ref = luaL_ref(lua, LUA_REGISTRYINDEX); lua_pushinteger(lua, ind_ovs_pktin_socket_netlink_port(&pktin_soc)); lua_setglobal(lua, "netlink_port"); }
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); } } } } }
void ind_cxn_bundle_ctrl_handle(connection_t *cxn, of_object_t *obj) { uint32_t bundle_id; uint16_t ctrl_type; uint16_t flags; uint16_t err_code = OFPBFC_UNKNOWN; of_bundle_ctrl_msg_bundle_id_get(obj, &bundle_id); of_bundle_ctrl_msg_bundle_ctrl_type_get(obj, &ctrl_type); of_bundle_ctrl_msg_flags_get(obj, &flags); bundle_t *bundle = find_bundle(cxn, bundle_id); if (ctrl_type == OFPBCT_OPEN_REQUEST) { if (bundle != NULL) { err_code = OFPBFC_BUNDLE_EXIST; goto error; } bundle = find_bundle(cxn, BUNDLE_ID_INVALID); if (bundle == NULL) { err_code = OFPBFC_OUT_OF_BUNDLES; goto error; } bundle->id = bundle_id; bundle->flags = flags; AIM_ASSERT(bundle->count == 0); AIM_ASSERT(bundle->allocated == 0); AIM_ASSERT(bundle->bytes == 0); AIM_ASSERT(bundle->msgs == NULL); } else if (ctrl_type == OFPBCT_CLOSE_REQUEST) { /* Ignored */ } else if (ctrl_type == OFPBCT_COMMIT_REQUEST) { if (bundle == NULL) { err_code = OFPBFC_BAD_ID; goto error; } if (comparator && !(bundle->flags & OFPBF_ORDERED)) { qsort(bundle->msgs, bundle->count, sizeof(bundle->msgs[0]), compare_message); } struct bundle_task_state *state = aim_zmalloc(sizeof(*state)); state->cxn_id = cxn->cxn_id; state->reply = of_object_dup(obj); of_bundle_ctrl_msg_bundle_ctrl_type_set(state->reply, OFPBCT_COMMIT_REPLY); state->id = bundle->id; state->count = bundle->count; state->offset = 0; state->msgs = bundle->msgs; if (ind_soc_task_register(bundle_task, state, IND_SOC_NORMAL_PRIORITY) < 0) { AIM_DIE("Failed to create long running task for bundle"); } ind_cxn_pause(cxn); /* Transfer ownership of msgs to task */ bundle->msgs = NULL; bundle->count = 0; free_bundle(bundle); /* Do not send reply yet */ return; } else if (ctrl_type == OFPBCT_DISCARD_REQUEST) { if (bundle == NULL) { err_code = OFPBFC_BAD_ID; goto error; } free_bundle(bundle); } else { err_code = OFPBFC_BAD_TYPE; goto error; } /* Send reply */ of_object_t *reply = of_object_dup(obj); /* Derive the reply subtype from the request */ of_bundle_ctrl_msg_bundle_ctrl_type_set(reply, ctrl_type+1); indigo_cxn_send_controller_message(cxn->cxn_id, reply); return; error: indigo_cxn_send_error_reply( cxn->cxn_id, obj, OF_ERROR_TYPE_BUNDLE_FAILED, err_code); }
void indigo_core_gentable_unregister(indigo_core_gentable_t *gentable) { AIM_ASSERT(gentable == (void *)1); }
int aim_main(int argc, char* argv[]) { of_list_bsn_tlv_t *key1, *key2, *value1, *value2, *value3; void *entry_priv; indigo_error_t rv; uint32_t ip; of_mac_addr_t mac; router_ip_table_init(); AIM_ASSERT(ops != NULL); key1 = make_key(10); key2 = make_key(8000); /* invalid */ value1 = make_value(0x1234, mac1); value2 = make_value(0x5678, mac2); value3 = make_value(0, mac1); /* invalid */ /* Successful add/modify/delete */ { rv = router_ip_table_lookup(10, &ip, &mac); AIM_ASSERT(rv == INDIGO_ERROR_NOT_FOUND); rv = ops->add(table_priv, key1, value1, &entry_priv); AIM_ASSERT(rv == INDIGO_ERROR_NONE); rv = router_ip_table_lookup(10, &ip, &mac); AIM_ASSERT(rv == INDIGO_ERROR_NONE); AIM_ASSERT(ip == 0x1234); AIM_ASSERT(!memcmp(&mac, &mac1, sizeof(of_mac_addr_t))); AIM_ASSERT(router_ip_check(ip) == true); AIM_ASSERT(router_ip_check(0x5678) == false); rv = ops->modify(table_priv, entry_priv, key1, value2); AIM_ASSERT(rv == INDIGO_ERROR_NONE); rv = router_ip_table_lookup(10, &ip, &mac); AIM_ASSERT(rv == INDIGO_ERROR_NONE); AIM_ASSERT(ip == 0x5678); AIM_ASSERT(!memcmp(&mac, &mac2, sizeof(of_mac_addr_t))); AIM_ASSERT(router_ip_check(ip) == true); AIM_ASSERT(router_ip_check(0x1234) == false); rv = ops->del(table_priv, entry_priv, key1); AIM_ASSERT(rv == INDIGO_ERROR_NONE); rv = router_ip_table_lookup(10, &ip, &mac); AIM_ASSERT(rv == INDIGO_ERROR_NOT_FOUND); AIM_ASSERT(router_ip_check(0x5678) == false); } /* Invalid key */ { rv = ops->add(table_priv, key2, value1, &entry_priv); AIM_ASSERT(rv == INDIGO_ERROR_PARAM); } /* Invalid value */ { rv = ops->add(table_priv, key1, value3, &entry_priv); AIM_ASSERT(rv == INDIGO_ERROR_PARAM); } of_object_delete(key1); of_object_delete(key2); of_object_delete(value1); of_object_delete(value2); of_object_delete(value3); router_ip_table_finish(); return 0; }
static void parse_options(int argc, char **argv) { while (1) { int option_index = 0; /* Options without short equivalents */ enum long_opts { OPT_START = 256, OPT_DPID, OPT_PIPELINE }; static struct option long_options[] = { {"verbose", no_argument, 0, 'v'}, {"trace", no_argument, 0, 't'}, {"controller", required_argument, 0, 'c'}, {"openflow-version", required_argument, 0, 'V'}, {"dpid", required_argument, 0, OPT_DPID}, {"pipeline", optional_argument, 0, OPT_PIPELINE} }; int c = getopt_long(argc, argv, "vt:c:hV:", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'v': loglevel = LOGLEVEL_VERBOSE; break; case 't': loglevel = LOGLEVEL_TRACE; break; case 'c': controllers = biglist_append(controllers, optarg); break; case 'V': openflow_version = optarg; break; case OPT_PIPELINE: pipeline = optarg ? optarg : "experimental"; break; case OPT_DPID: AIM_ASSERT(optarg != NULL, "clang-analyzer workaround"); dpid = strtoll(optarg, NULL, 16); break; case 'h': case '?': printf("ofagent: Indigo OpenNSL Integration\n"); printf("Usage: ofagent [OPTION]...\n"); printf("\n"); printf(" -v, --verbose verbose\n"); printf(" -t, --trace Very verbose logging\n"); printf(" -c, --controller=IP:PORT Connect to a controller at startup\n"); printf(" --pipeline=NAME Set the default forwarding pipeline (standard-1.0 or standard-1.3)\n"); printf(" --dpid=DPID Set datapath ID (default autogenerated)\n"); printf(" --syslog Log to syslog instead of stderr\n"); printf(" -h,--help Display this help message and exit\n"); printf(" --version Display version information and exit\n"); exit(c == 'h' ? 0 : 1); break; } } }
static void parse_options(int argc, char **argv) { while (1) { int option_index = 0; /* Options without short equivalents */ enum long_opts { OPT_START = 256, OPT_NAME, OPT_DPID, OPT_SYSLOG, OPT_TUNNEL, OPT_VERSION, OPT_MAX_FLOWS, OPT_PIPELINE, }; static struct option long_options[] = { {"verbose", no_argument, 0, 'v' }, {"trace", no_argument, 0, 't' }, {"interface", required_argument, 0, 'i' }, {"controller", required_argument, 0, 'c' }, {"listen", required_argument, 0, 'l' }, {"pipeline", optional_argument, 0, OPT_PIPELINE }, {"dpid", required_argument, 0, OPT_DPID }, {"syslog", no_argument, 0, OPT_SYSLOG }, {"tunnel", no_argument, 0, OPT_TUNNEL }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, OPT_VERSION }, /* Undocumented options */ {"name", required_argument, 0, OPT_NAME }, {"max-flows", required_argument, 0, OPT_MAX_FLOWS }, {"config-file", required_argument, 0, 'f' }, {"openflow-version", required_argument, 0, 'V' }, {0, 0, 0, 0 } }; int c = getopt_long(argc, argv, "vtl:i:c:f:hV:", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'v': loglevel = LOGLEVEL_VERBOSE; break; case 't': loglevel = LOGLEVEL_TRACE; break; case 'c': controllers = biglist_append(controllers, optarg); break; case 'l': listeners = biglist_append(listeners, optarg); break; case 'i': interfaces = biglist_append(interfaces, optarg); break; case 'f': config_filename = optarg; break; case 'V': openflow_version = optarg; break; case OPT_NAME: datapath_name = strdup(optarg); break; case OPT_DPID: AIM_ASSERT(optarg != NULL, "clang-analyzer workaround"); dpid = strtoll(optarg, NULL, 16); break; case OPT_SYSLOG: use_syslog = 1; break; case OPT_TUNNEL: enable_tunnel = 1; break; case OPT_VERSION: printf("%s (%s)\n", program_version, AIM_STRINGIFY(BUILD_ID)); exit(0); break; case OPT_MAX_FLOWS: AIM_ASSERT(optarg != NULL, "clang-analyzer workaround"); max_flows = strtoll(optarg, NULL, 0); core_cfg.max_flowtable_entries = max_flows; AIM_LOG_MSG("Setting max flows to %d", max_flows); break; case OPT_PIPELINE: pipeline = optarg ? optarg : "experimental"; break; case 'h': case '?': printf("ivs: Indigo Virtual Switch\n"); printf("Usage: ivs [OPTION]...\n"); printf("\n"); printf(" -v, --verbose Verbose logging\n"); printf(" -t, --trace Very verbose logging\n"); printf(" -c, --controller=IP:PORT Connect to a controller at startup\n"); printf(" -l, --listen=IP:PORT Listen for dpctl connections\n"); printf(" -i, --interface=INTERFACE Attach a network interface at startup\n"); printf(" --pipeline=NAME Set the default forwarding pipeline (standard-1.0 or standard-1.3)\n"); //printf(" -f, --config-file=FILE Read a configuration file\n"); //printf(" --name=NAME Set the name of the kernel datapath (default indigo)\n"); printf(" --dpid=DPID Set datapath ID (default autogenerated)\n"); printf(" --syslog Log to syslog instead of stderr\n"); printf(" --tunnel Enable flow-based GRE tunneling (requires controller support)\n"); printf(" -h,--help Display this help message and exit\n"); printf(" --version Display version information and exit\n"); exit(c == 'h' ? 0 : 1); break; } } }