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);
}
Exemple #2
0
/* 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;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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");
    }
}
Exemple #6
0
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);
}
Exemple #7
0
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);
}
Exemple #9
0
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);
}