void ind_core_bsn_table_checksum_stats_request_handler(of_object_t *_obj, indigo_cxn_id_t cxn_id) { of_bsn_table_checksum_stats_request_t *obj = _obj; of_bsn_table_checksum_stats_reply_t *reply; of_list_bsn_table_checksum_stats_entry_t entries; of_bsn_table_checksum_stats_entry_t *entry; uint32_t xid; uint8_t table_id; reply = of_bsn_table_checksum_stats_reply_new(obj->version); AIM_TRUE_OR_DIE(reply != NULL); of_bsn_table_checksum_stats_request_xid_get(obj, &xid); of_bsn_table_checksum_stats_reply_xid_set(reply, xid); of_bsn_table_checksum_stats_reply_entries_bind(reply, &entries); entry = of_bsn_table_checksum_stats_entry_new(entries.version); AIM_TRUE_OR_DIE(entry != NULL); for (table_id = 0; table_id < FT_MAX_TABLES; table_id++) { ft_table_t *table = &ind_core_ft->tables[table_id]; of_bsn_table_checksum_stats_entry_table_id_set(entry, table_id); of_bsn_table_checksum_stats_entry_checksum_set(entry, table->checksum); if (of_list_append(&entries, entry) < 0) { /* This entry didn't fit, send out the current message and * allocate a new one. */ of_bsn_table_checksum_stats_reply_flags_set( reply, OF_STATS_REPLY_FLAG_REPLY_MORE); indigo_cxn_send_controller_message(cxn_id, reply); reply = of_bsn_table_checksum_stats_reply_new(obj->version); AIM_TRUE_OR_DIE(reply != NULL); of_bsn_table_checksum_stats_reply_xid_set(reply, xid); of_bsn_table_checksum_stats_reply_entries_bind(reply, &entries); if (of_list_append(&entries, entry) < 0) { AIM_DIE("unexpected failure appending single bsn_table_checksum stats entry"); } } } of_object_delete(entry); indigo_cxn_send_controller_message(cxn_id, reply); }
/* Handle a packet in from forwarding */ indigo_error_t indigo_core_packet_in(of_packet_in_t *packet_in) { int rv; if (!ind_core_module_enabled) { LOG_TRACE("Packet in called when not enabled"); of_object_delete(packet_in); return INDIGO_ERROR_INIT; } LOG_TRACE("Packet in rcvd"); ind_core_packet_ins++; rv = indigo_cxn_send_controller_message(INDIGO_CXN_ID_UNSPECIFIED, packet_in); /* PAN-163. Not sure why these get printed out; changed to TRACE */ /* Don't log error when there is no preferred connection in cxn manager */ if (rv != INDIGO_ERROR_NONE && rv != INDIGO_ERROR_NOT_READY) { LOG_TRACE("Error forwarding packet in to controller"); } return rv; }
static void cxn_msg_rx(indigo_cxn_id_t cxn_id, of_object_t *obj) { printf("Got msg from %d: type %d\n", cxn_id, obj->object_id); /* Just respond to echo request */ if (obj->object_id == OF_ECHO_REQUEST) { of_echo_request_t *echo; of_echo_reply_t *reply; of_octets_t data; uint32_t xid; echo = (of_echo_request_t *)obj; of_echo_request_xid_get(echo, &xid); printf("Respond to echo with xid 0x%x\n", xid); if ((reply = of_echo_reply_new(echo->version)) == NULL) { printf("Could not allocate echo response obj\n"); goto done; } of_echo_request_data_get(echo, &data); if (data.bytes) { OK(of_echo_reply_data_set(reply, &data)); } of_echo_reply_xid_set(reply, xid); indigo_cxn_send_controller_message(cxn_id, reply); } done: of_object_delete(obj); got_cxn_msg = 1; }
static void send_flow_removed_message(ft_entry_t *entry, indigo_fi_flow_removed_t reason) { of_flow_removed_t *msg; int rv = 0; uint32_t secs; uint32_t nsecs; indigo_time_t current; current = INDIGO_CURRENT_TIME; /* TODO get version from OFConnectionManager */ if ((msg = of_flow_removed_new(entry->match.version)) == NULL) { return; } calc_duration(current, entry->insert_time, &secs, &nsecs); of_flow_removed_xid_set(msg, ind_core_xid_alloc()); of_flow_removed_cookie_set(msg, entry->cookie); of_flow_removed_priority_set(msg, entry->priority); of_flow_removed_idle_timeout_set(msg, entry->idle_timeout); if (msg->version >= OF_VERSION_1_1) { of_flow_removed_table_id_set(msg, entry->table_id); } if (msg->version >= OF_VERSION_1_2) { of_flow_removed_hard_timeout_set(msg, entry->hard_timeout); } if (of_flow_removed_match_set(msg, &entry->match)) { LOG_ERROR("Failed to set match in flow removed message"); of_object_delete(msg); return; } if (reason > INDIGO_FLOW_REMOVED_DELETE) { /* Normalize entry */ reason = INDIGO_FLOW_REMOVED_DELETE; } of_flow_removed_reason_set(msg, reason); of_flow_removed_duration_sec_set(msg, secs); of_flow_removed_duration_nsec_set(msg, nsecs); of_flow_removed_packet_count_set(msg, entry->packets); of_flow_removed_byte_count_set(msg, entry->bytes); /* @fixme hard_timeout and table_id are not in OF 1.0 */ /* @fixme Should a cxn-id be specified? */ rv = indigo_cxn_send_controller_message(INDIGO_CXN_ID_UNSPECIFIED, msg); if (rv != INDIGO_ERROR_NONE) { LOG_ERROR("Error sending flow removed message"); return; } return; }
void indigo_core_port_status_update(of_port_status_t *of_port_status) { int rv; /* * Special case: We allow this call to pass thru even if not enabled. */ LOG_TRACE("OF state mgr port status update"); rv = indigo_cxn_send_controller_message(INDIGO_CXN_ID_UNSPECIFIED, of_port_status); /* Don't log error if controller is not connected */ if (rv != INDIGO_ERROR_NONE && rv != INDIGO_ERROR_NOT_READY) { LOG_ERROR("Error sending port status message to controller"); } }
static void handle_lua_command_request(indigo_cxn_id_t cxn_id, of_object_t *msg) { const int max_reply_size = UINT16_MAX - of_object_fixed_len[msg->version][OF_BSN_LUA_COMMAND_REPLY]; uint32_t xid; of_octets_t request_data; of_bsn_lua_command_request_xid_get(msg, &xid); of_bsn_lua_command_request_data_get(msg, &request_data); pipeline_lua_allocator_reset(); void *request_buf = pipeline_lua_allocator_dup(request_data.data, request_data.bytes); void *reply_buf = pipeline_lua_allocator_alloc(max_reply_size); lua_rawgeti(lua, LUA_REGISTRYINDEX, command_ref); lua_pushlightuserdata(lua, request_buf); lua_pushinteger(lua, request_data.bytes); lua_pushlightuserdata(lua, reply_buf); lua_pushinteger(lua, max_reply_size); if (lua_pcall(lua, 4, 1, 0) != 0) { AIM_LOG_ERROR("Failed to execute command xid=%#x: %s", xid, lua_tostring(lua, -1)); indigo_cxn_send_error_reply( cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM); return; } int reply_size = lua_tointeger(lua, 0); AIM_TRUE_OR_DIE(reply_size >= 0 && reply_size < max_reply_size); lua_settop(lua, 0); of_object_t *reply = of_bsn_lua_command_reply_new(msg->version); of_bsn_lua_command_reply_xid_set(reply, xid); of_octets_t reply_data = { .data = reply_buf, .bytes = reply_size }; if (of_bsn_lua_command_reply_data_set(reply, &reply_data) < 0) { AIM_DIE("Unexpectedly failed to set data in of_bsn_lua_command_reply"); } indigo_cxn_send_controller_message(cxn_id, reply); }
static ind_soc_task_status_t bundle_task(void *cookie) { struct bundle_task_state *state = cookie; connection_t *cxn = ind_cxn_id_to_connection(state->cxn_id); while (state->offset < state->count) { if (cxn) { of_object_storage_t obj_storage; of_object_t *obj = parse_message(state->msgs[state->offset], &obj_storage); ind_cxn_process_message(cxn, obj); } else { /* Connection went away. Drop remaining messages. */ } aim_free(state->msgs[state->offset]); state->msgs[state->offset] = NULL; state->offset++; if (ind_soc_should_yield()) { return IND_SOC_TASK_CONTINUE; } } if (cxn) { indigo_cxn_send_controller_message(cxn->cxn_id, state->reply); } else { of_object_delete(state->reply); } aim_free(state->msgs); aim_free(state); if (cxn) { ind_cxn_resume(cxn); } return IND_SOC_TASK_FINISHED; }
void ind_core_bsn_flow_checksum_bucket_stats_request_handler(of_object_t *_obj, indigo_cxn_id_t cxn_id) { of_bsn_flow_checksum_bucket_stats_request_t *obj = _obj; of_bsn_flow_checksum_bucket_stats_reply_t *reply; of_list_bsn_flow_checksum_bucket_stats_entry_t entries; of_bsn_flow_checksum_bucket_stats_entry_t *entry; uint32_t xid; uint8_t table_id; ft_table_t *table; int bucket_idx; of_bsn_flow_checksum_bucket_stats_request_table_id_get(obj, &table_id); if (table_id >= FT_MAX_TABLES) { AIM_LOG_WARN("Invalid table ID %u", table_id); indigo_cxn_send_error_reply(cxn_id, obj, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM); return; } table = &ind_core_ft->tables[table_id]; reply = of_bsn_flow_checksum_bucket_stats_reply_new(obj->version); AIM_TRUE_OR_DIE(reply != NULL); of_bsn_flow_checksum_bucket_stats_request_xid_get(obj, &xid); of_bsn_flow_checksum_bucket_stats_reply_xid_set(reply, xid); of_bsn_flow_checksum_bucket_stats_reply_entries_bind(reply, &entries); entry = of_bsn_flow_checksum_bucket_stats_entry_new(entries.version); AIM_TRUE_OR_DIE(entry != NULL); for (bucket_idx = 0; bucket_idx < table->checksum_buckets_size; bucket_idx++) { of_bsn_flow_checksum_bucket_stats_entry_checksum_set( entry, table->checksum_buckets[bucket_idx]); if (of_list_append(&entries, entry) < 0) { /* This entry didn't fit, send out the current message and * allocate a new one. */ of_bsn_flow_checksum_bucket_stats_reply_flags_set( reply, OF_STATS_REPLY_FLAG_REPLY_MORE); indigo_cxn_send_controller_message(cxn_id, reply); reply = of_bsn_flow_checksum_bucket_stats_reply_new(obj->version); AIM_TRUE_OR_DIE(reply != NULL); of_bsn_flow_checksum_bucket_stats_reply_xid_set(reply, xid); of_bsn_flow_checksum_bucket_stats_reply_entries_bind(reply, &entries); if (of_list_append(&entries, entry) < 0) { AIM_DIE("unexpected failure appending single bsn_flow_checksum_bucket stats entry"); } } } of_object_delete(entry); indigo_cxn_send_controller_message(cxn_id, reply); }
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); }