Esempio n. 1
0
void
ind_cxn_bundle_add_handle(connection_t *cxn, of_object_t *obj)
{
    uint32_t bundle_id;
    uint16_t flags;
    of_octets_t data;

    of_bundle_add_msg_bundle_id_get(obj, &bundle_id);
    of_bundle_add_msg_flags_get(obj, &flags);
    of_bundle_add_msg_data_get(obj, &data);

    bundle_t *bundle = find_bundle(cxn, bundle_id);
    if (bundle == NULL) {
        indigo_cxn_send_error_reply(
            cxn->cxn_id, obj,
            OF_ERROR_TYPE_BUNDLE_FAILED,
            OFPBFC_BAD_ID);
        return;
    }

    /* Validate length */
    if (data.bytes < OF_MESSAGE_HEADER_LENGTH || data.bytes != of_message_length_get(data.data)) {
        indigo_cxn_send_error_reply(
            cxn->cxn_id, obj,
            OF_ERROR_TYPE_BUNDLE_FAILED,
            OFPBFC_MSG_BAD_LEN);
        AIM_LOG_WARN("Inconsistent bundled message length", bundle->id);
        return;
    }

    /* Limit number of messages in the bundle */
    if (bundle->count >= OFCONNECTIONMANAGER_CONFIG_MAX_BUNDLE_MSGS) {
        indigo_cxn_send_error_reply(
            cxn->cxn_id, obj,
            OF_ERROR_TYPE_BUNDLE_FAILED,
            OFPBFC_MSG_TOO_MANY);
        AIM_LOG_WARN("Exceeded maximum number (%u) of messages in bundle %u", OFCONNECTIONMANAGER_CONFIG_MAX_BUNDLE_MSGS, bundle->id);
        return;
    }

    /* Limit amount of memory used by the bundle */
    if ((bundle->bytes + data.bytes) > OFCONNECTIONMANAGER_CONFIG_MAX_BUNDLE_BYTES) {
        indigo_cxn_send_error_reply(
            cxn->cxn_id, obj,
            OF_ERROR_TYPE_BUNDLE_FAILED,
            OFPBFC_MSG_TOO_MANY);
        AIM_LOG_WARN("Exceeded maximum size (%u bytes) of messages in bundle %u", OFCONNECTIONMANAGER_CONFIG_MAX_BUNDLE_BYTES, bundle->id);
        return;
    }

    if (bundle->count == bundle->allocated) {
        /* Resize array */
        uint32_t new_allocated = (bundle->allocated == 0 ? 1 : bundle->allocated * 2);
        bundle->msgs = aim_realloc(bundle->msgs, sizeof(*bundle->msgs) * new_allocated);
        bundle->allocated = new_allocated;
    }

    bundle->msgs[bundle->count++] = aim_memdup(data.data, data.bytes);
    bundle->bytes += data.bytes;
}
Esempio n. 2
0
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
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);
    }
}
Esempio n. 4
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);
}
Esempio n. 5
0
static void
commit_lua_upload(indigo_cxn_id_t cxn_id, of_object_t *msg)
{
    uint16_t flags;
    of_bsn_lua_upload_flags_get(msg, &flags);

    /* TODO use stronger hash function */
    uint32_t new_checksum = murmur_hash(xbuf_data(&upload_chunks),
                                        xbuf_length(&upload_chunks),
                                        0);
    if (!(flags & OFP_BSN_LUA_UPLOAD_FORCE) && checksum == new_checksum) {
        AIM_LOG_VERBOSE("Skipping Lua commit, checksums match");
        goto cleanup;
    }

    checksum = 0;

    reset_lua();

    uint32_t offset = 0;
    while (offset < xbuf_length(&upload_chunks)) {
        struct upload_chunk *chunk = xbuf_data(&upload_chunks) + offset;
        offset += sizeof(*chunk) + chunk->size;

        AIM_LOG_VERBOSE("Loading Lua chunk %s, %u bytes", chunk->filename, chunk->size);

        char name[64];
        snprintf(name, sizeof(name), "=%s", chunk->filename);

        if (luaL_loadbuffer(lua, chunk->data, chunk->size, name) != 0) {
            AIM_LOG_ERROR("Failed to load code: %s", lua_tostring(lua, -1));
            indigo_cxn_send_error_reply(
                cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM);
            goto cleanup;
        }

        /* Set the environment of the new chunk to the sandbox */
        lua_getglobal(lua, "sandbox");
        lua_setfenv(lua, -2);

        if (lua_pcall(lua, 0, 1, 0) != 0) {
            AIM_LOG_ERROR("Failed to execute code %s: %s", chunk->filename, lua_tostring(lua, -1));
            indigo_cxn_send_error_reply(
                cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM);
            goto cleanup;
        }

        /* Save the return value in the "modules" table, used by require */
        char *module_name = aim_strdup(chunk->filename);
        char *dot = strrchr(module_name, '.');
        if (dot) *dot = 0; /* strip file extension */
        lua_getglobal(lua, "modules");
        lua_pushstring(lua, module_name);
        lua_pushvalue(lua, -3); /* return value from pcall */
        lua_rawset(lua, -3); /* modules[filename] = return_value */
        lua_pop(lua, 2); /* pop modules and return value */
        free(module_name);
    }

    checksum = new_checksum;

cleanup:
    cleanup_lua_upload();
    return;
}
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);
}
Esempio n. 7
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);
}