Exemple #1
0
void indigo_core_table_register(uint8_t table_id, const char *name,
                                const indigo_core_table_ops_t *ops, void *priv)
{
    AIM_TRUE_OR_DIE(strlen(name) <= OF_MAX_TABLE_NAME_LEN);

    list_links_t *cur, *next;
    ft_entry_t *entry;
    FT_ITER(ind_core_ft, entry, cur, next) {
        if (entry->table_id == table_id) {
            ind_core_flow_entry_delete(entry, OF_FLOW_REMOVED_REASON_DELETE,
                                       INDIGO_CXN_ID_UNSPECIFIED);
        }
    }

    ind_core_table_t *table = aim_zmalloc(sizeof(*table));
    strncpy(table->name, name, sizeof(table->name));
    table->ops = ops;
    table->priv = priv;
    table->num_flows = 0;

    AIM_TRUE_OR_DIE(ind_core_tables[table_id] == NULL);
    ind_core_tables[table_id] = table;
    ind_core_num_tables_registered++;

    AIM_LOG_VERBOSE("Registered flowtable \"%s\" with table id %d", name, table_id);
}
static int
test_port_stats(void)
{
    struct ind_core_port *handle1, *handle2;
    indigo_core_port_register(1, &handle1);
    indigo_core_port_register(2, &handle2);

    /* Request for OFPP_ANY */
    memset(port_counters, 0, sizeof(port_counters));
    of_port_stats_request_t *obj = of_port_stats_request_new(OF_VERSION_1_4);
    of_port_stats_request_port_no_set(obj, OF_PORT_DEST_WILDCARD);
    handle_message(obj);
    do_barrier();

    AIM_TRUE_OR_DIE(port_counters[1].stats == 1);
    AIM_TRUE_OR_DIE(port_counters[2].stats == 1);

    /* Request for a single port */
    memset(port_counters, 0, sizeof(port_counters));
    obj = of_port_stats_request_new(OF_VERSION_1_4);
    of_port_stats_request_port_no_set(obj, 2);
    handle_message(obj);
    do_barrier();

    AIM_TRUE_OR_DIE(port_counters[1].stats == 0);
    AIM_TRUE_OR_DIE(port_counters[2].stats == 1);

    indigo_core_port_unregister(handle1);
    indigo_core_port_unregister(handle2);

    return TEST_PASS;
}
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);
}
static int
test_queue_desc_stats_multipart(void)
{
    int i, j;
    struct ind_core_port *port_handles[OFSTATEMANAGER_CONFIG_MAX_PORTS];
    struct ind_core_queue *queue_handles[OFSTATEMANAGER_CONFIG_MAX_PORTS];
    const int qid = 3;

    for (i = 0; i < OFSTATEMANAGER_CONFIG_MAX_PORTS; i++) {
        indigo_core_port_register(i, &port_handles[i]);
        indigo_core_queue_register(i, qid, &queue_handles[i]);
    }

    memset(port_counters, 0, sizeof(port_counters));
    of_queue_desc_stats_request_t *obj = of_queue_desc_stats_request_new(OF_VERSION_1_4);
    of_queue_desc_stats_request_port_no_set(obj, OF_PORT_DEST_WILDCARD);
    of_queue_desc_stats_request_queue_id_set(obj, OF_QUEUE_ALL);
    handle_message(obj);
    do_barrier();

    for (i = 0; i < OFSTATEMANAGER_CONFIG_MAX_PORTS; i++) {
        for (j = 0; j < QUEUES_PER_PORT; j++) {
            AIM_TRUE_OR_DIE(port_counters[i].queue_desc_stats[j] ==
                            (j == qid)? 1: 0);
        }
    }

    for (i = 0; i < OFSTATEMANAGER_CONFIG_MAX_PORTS; i++) {
        indigo_core_queue_unregister(queue_handles[i]);
        indigo_core_port_unregister(port_handles[i]);
    }

    return TEST_PASS;
}
Exemple #5
0
static int
os_sem_take_timeout_sem__(os_sem_t sem, uint64_t usecs)
{
    AIM_TRUE_OR_DIE(!USES_EFD(sem), "timout_sem__ called while EFD in use.");

    if(usecs == 0) {
        /** Normal wait */
        return os_sem_take(sem);
    }
    else {

        struct timespec ts;
        timespec_init_timeout__(&ts, usecs);

        for(;;) {
            if(sem_timedwait(&sem->sem, &ts) == 0) {
                return 0;
            }
            switch(errno)
                {
                case EINTR:
                    break;
                case ETIMEDOUT:
                    return -1;

                case EINVAL:
                    AIM_DIE("Invalid or corrupted semaphore or the timespec was invalid in os_sem_take_timeout().");
                    break;
                default:
                    AIM_DIE("Unhandled error condition in os_sem_take() for errno=%{errno}", errno);
                    break;
                }
        }
    }
}
Exemple #6
0
static of_list_bsn_tlv_t *
make_value (uint32_t vr_ip, of_mac_addr_t mac,
            uint32_t dhcp_ser_ip, of_octets_t *cid)
{
    of_list_bsn_tlv_t *list = of_list_bsn_tlv_new(OF_VERSION_1_3);
    {
        of_bsn_tlv_ipv4_t *tlv = of_bsn_tlv_ipv4_new(OF_VERSION_1_3);
        of_bsn_tlv_ipv4_value_set(tlv, vr_ip);
        of_list_append(list, tlv);
        of_object_delete(tlv);
    }
    {
        of_bsn_tlv_mac_t *tlv = of_bsn_tlv_mac_new(OF_VERSION_1_3);
        of_bsn_tlv_mac_value_set(tlv, mac);
        of_list_append(list, tlv);
        of_object_delete(tlv);
    }
    {
        of_bsn_tlv_ipv4_t *tlv = of_bsn_tlv_ipv4_new(OF_VERSION_1_3);
        of_bsn_tlv_ipv4_value_set(tlv, dhcp_ser_ip);
        of_list_append(list, tlv);
        of_object_delete(tlv);
    }
    {
        of_bsn_tlv_circuit_id_t *tlv = of_bsn_tlv_circuit_id_new(OF_VERSION_1_3);
        AIM_TRUE_OR_DIE(of_bsn_tlv_circuit_id_value_set(tlv, cid) == OF_ERROR_NONE);
        of_list_append(list, tlv);
        of_object_delete(tlv);
    }
    return list;
}
Exemple #7
0
void del_entry_to_dhcpr_table()
{

    of_list_bsn_tlv_t *key;
    dhc_relay_t       *dhc_relay;
    uint32_t          vlan_id = 1;
    uint32_t          vlan_ret = 0;


    printf("\nVlan %d Delete to dhcp table\n", vlan_id);

    if (! (dhc_relay = dhcpr_get_dhcpr_entry_from_vlan_table(vlan_id))) {
        printf("Error get_dhcp_conf Vlan %d\n", vlan_id);
    }

    key = make_key(vlan_id);

    ops->del(table_priv, dhc_relay, key);

    /* Test 3: routerip -> vlan
     * invalid vlan, no need to check circuit
     */
    dhcpr_virtual_router_key_to_vlan(&vlan_ret, dummy_dhcp_opt_info.vrouter_ip, dummy_dhcp_opt_info.vrouter_mac.addr);
    printf("router_ip_to_vlan = %d\n", vlan_ret);
    AIM_TRUE_OR_DIE(vlan_ret==INVALID_VLAN);

   printf("\nVlan %d Delete entry\n", vlan_id);
}
static int
test_port_stats_multipart(void)
{
    int i;
    struct ind_core_port *port_handles[OFSTATEMANAGER_CONFIG_MAX_PORTS];

    for (i = 0; i < OFSTATEMANAGER_CONFIG_MAX_PORTS; i++) {
        indigo_core_port_register(i, &port_handles[i]);
    }

    memset(port_counters, 0, sizeof(port_counters));
    of_port_stats_request_t *obj = of_port_stats_request_new(OF_VERSION_1_4);
    of_port_stats_request_port_no_set(obj, OF_PORT_DEST_WILDCARD);
    handle_message(obj);
    do_barrier();

    for (i = 0; i < OFSTATEMANAGER_CONFIG_MAX_PORTS; i++) {
        AIM_TRUE_OR_DIE(port_counters[i].stats == 1);
    }

    for (i = 0; i < OFSTATEMANAGER_CONFIG_MAX_PORTS; i++) {
        indigo_core_port_unregister(port_handles[i]);
    }

    return TEST_PASS;
}
Exemple #9
0
void add_entry_to_dhcpr_table()
{
    indigo_error_t rv;
    int i;
    of_list_bsn_tlv_t *key, *value;
    void              *entry_priv;

    //Test
    dhc_relay_t       *dc;
    uint32_t          vlan;
    uint32_t          vr_ip = dummy_dhcp_opt_info.vrouter_ip+1;
    //Only add Vlan1 for now
    for (i=1; i<2; i++) {
        key = make_key(i);
        value = make_value(vr_ip,
                dummy_dhcp_opt_info.vrouter_mac,
                dummy_dhcp_opt_info.dhcp_server_ip,
                &dummy_cir_id2);

        //Test Add
        if((rv = ops->add(table_priv, key, value, &entry_priv)) != INDIGO_ERROR_NONE) {
            printf("Error Add table rv=%u", rv);
            exit(1);
        } else {
            printf("\nVlan %d Added to dhcp table\n", i);

            /* Test 1: dhcp conf array */
            if (! (dc = dhcpr_get_dhcpr_entry_from_vlan_table(i))) {
                printf("Error get_dhcp_conf Vlan %d\n", i);
            }

            /* Test 2: cir -> vlan */
            vlan = 1;
            AIM_TRUE_OR_DIE(!dhcpr_circuit_id_vlan_check(vlan, dummy_cir_id2.data,
                                                         dummy_cir_id2.bytes ));

            /* Test 3: routerip -> vlan */
            dhcpr_virtual_router_key_to_vlan(&vlan, vr_ip, dummy_dhcp_opt_info.vrouter_mac.addr);
            printf("router_ip_to_vlan = %u, vr_ip = %s\n",
                        vlan, inet_ntoa(*(struct in_addr *) &vr_ip));
            AIM_TRUE_OR_DIE(vlan==1);

            printf("DHCP CONF TABLE ok\n");
        }

    }
}
Exemple #10
0
void add_entry_to_dhcpr_table()
{
    indigo_error_t rv;
    int i;
    of_list_bsn_tlv_t *key, *value;
    void              *entry_priv;

    //Test
    dhc_relay_t       *dc;
    uint32_t          vlan;

    //Only add Vlan1 for now
    for (i=VLAN_TEST; i<=VLAN_TEST; i++) {
        key = make_key(i);
        value = make_value(dummy_dhcp_opt_info.vrouter_ip,
                dummy_dhcp_opt_info.vrouter_mac,
                dummy_dhcp_opt_info.dhcp_server_ip,
                &dummy_dhcp_opt_info.opt_id.circuit_id);
        if((rv = ops->add(table_priv, key, value, &entry_priv)) != INDIGO_ERROR_NONE) {
            printf("Error Add table rv=%u", rv);
            exit(1);
        } else {
            printf("\nVlan %d Added to dhcp table\n", i);

            /* Test 1: dhcp conf array */
            if (! (dc = dhcpr_get_dhcpr_entry_from_vlan_table(i))) {
                printf("Error get_dhcp_conf Vlan %d\n", i);
            }

            /* Test 2: cir -> vlan */
            dhcpr_circuit_id_to_vlan(&vlan, dummy_dhcp_opt_info.opt_id.circuit_id.data,
                                                dummy_dhcp_opt_info.opt_id.circuit_id.bytes );
            printf("circuit_id_to_vlan = %u\n", vlan);
            AIM_TRUE_OR_DIE(vlan==1);

            /* Test 3: routerip -> vlan */
            dhcpr_virtual_router_ip_to_vlan(&vlan, dummy_dhcp_opt_info.vrouter_ip);
            printf("router_ip_to_vlan = %u\n", vlan);
            AIM_TRUE_OR_DIE(vlan==1);

            printf("DHCP CONF TABLE ok\n");
        }
    }
}
Exemple #11
0
void mod_entry_to_dhcpr_table()
{

    of_list_bsn_tlv_t *key, *value;
    dhc_relay_t       *dhc_relay;
    uint32_t          vlan_id = 1;
    uint32_t          vlan_ret = 0;

    printf("\nVlan %d Modify to dhcp table\n", vlan_id);

    if (! (dhc_relay = dhcpr_get_dhcpr_entry_from_vlan_table(vlan_id))) {
        printf("Error get_dhcp_conf Vlan %d\n", vlan_id);
    }

    key = make_key(vlan_id);
    value = make_value(dummy_dhcp_opt_info.vrouter_ip,
                dummy_dhcp_opt_info.vrouter_mac,
                dummy_dhcp_opt_info.dhcp_server_ip,
                &dummy_dhcp_opt_info.opt_id.circuit_id);

    ops->modify(table_priv, dhc_relay, key, value);
    /* Test 3: routerip -> vlan
     * Invalid_vlan, no need to check against circuit
     */
    dhcpr_virtual_router_key_to_vlan(&vlan_ret, dummy_dhcp_opt_info.vrouter_ip+1, dummy_dhcp_opt_info.vrouter_mac.addr);
    printf("router_ip_to_vlan = %d\n", vlan_ret);
    AIM_TRUE_OR_DIE(vlan_ret==INVALID_VLAN);


    /* Test 4: cir -> vlan */
    vlan_ret = vlan_id;
    AIM_TRUE_OR_DIE(!dhcpr_circuit_id_vlan_check(vlan_ret, dummy_dhcp_opt_info.opt_id.circuit_id.data,
                                                 dummy_dhcp_opt_info.opt_id.circuit_id.bytes ));

   /* Test 5: routerip -> vlan */
   dhcpr_virtual_router_key_to_vlan(&vlan_ret, dummy_dhcp_opt_info.vrouter_ip, dummy_dhcp_opt_info.vrouter_mac.addr);
   printf("router_ip_to_vlan = %d\n", vlan_ret);
   AIM_TRUE_OR_DIE(vlan_ret==vlan_id);

   printf("\nVlan %d Modify to dhcp table change virtual routerIP and circuit \n", vlan_id);
}
static int
test_port_desc_stats(void)
{
    struct ind_core_port *handle1, *handle2;
    indigo_core_port_register(1, &handle1);
    indigo_core_port_register(2, &handle2);

    memset(port_counters, 0, sizeof(port_counters));

    of_port_desc_stats_request_t *obj = of_port_desc_stats_request_new(OF_VERSION_1_4);
    handle_message(obj);
    do_barrier();

    AIM_TRUE_OR_DIE(port_counters[1].desc_stats == 1);
    AIM_TRUE_OR_DIE(port_counters[2].desc_stats == 1);

    indigo_core_port_unregister(handle1);
    indigo_core_port_unregister(handle2);

    return TEST_PASS;
}
/*
 * 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;
}
Exemple #14
0
void indigo_core_table_unregister(uint8_t table_id)
{
    ind_core_table_t *table = ind_core_tables[table_id];
    AIM_TRUE_OR_DIE(table != NULL);

    list_links_t *cur, *next;
    ft_entry_t *entry;
    FT_ITER(ind_core_ft, entry, cur, next) {
        if (entry->table_id == table_id) {
            ind_core_flow_entry_delete(entry, OF_FLOW_REMOVED_REASON_DELETE,
                                       INDIGO_CXN_ID_UNSPECIFIED);
        }
    }

    aim_free(table);
    ind_core_tables[table_id] = NULL;
    ind_core_num_tables_registered--;
}
Exemple #15
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 #16
0
int fill_all_vlan_dhcpr_table_test()
{
    indigo_error_t rv;
    of_list_bsn_tlv_t *key, *value;
    void              *entry_priv;
    dhc_relay_t       *dhc_relay;

    int k;
    int vlan_no;
    int vr_ip_no;

    uint32_t      virtualRouterIP = 1;
    of_mac_addr_t mac = { .addr = {0x55, 0x16, 0xc7, 0x01, 0x02, 0x03} };
    uint32_t      dhcpServerIP    = 2;
    uint16_t      cir_value[VLAN_MAX+1];
    of_octets_t   cir_id;

    int num_of_vlan = VLAN_MAX;
    int extra_vlan = 2; //Test error

    //NOTE: no need to do htonl or htons,
    //What ever value we send here, we get over there
    //No need to convert.

    //Initialize cir_value
    for (k = 0; k <= num_of_vlan; k++) {
        cir_value[k] = (k+1);
    }


    printf("TEST:1 fill all\n");
    /* Add 1st half having circuit */
    for (k = 0; k < num_of_vlan/2 ; k++) {

        cir_id.bytes = sizeof(cir_value[k]);
        cir_id.data  = (uint8_t*)&cir_value[k];

        key = make_key(k);
        value = make_value((virtualRouterIP+k),
                           mac,
                           (dhcpServerIP+k),
                           &cir_id);

        if((rv = ops->add(table_priv, key, value, &entry_priv)) != INDIGO_ERROR_NONE) {
            printf("Error out of range table %u, rv=%u", k, rv);
            exit(1);
        }
    }

    /* Add 2nd half non circuit */
    printf("Range k=%u - %u\n", num_of_vlan/2, num_of_vlan);
    for (k = num_of_vlan/2; k<= num_of_vlan+extra_vlan ; k++) {
        key = make_key(k);
        value = make_value((virtualRouterIP+k),
                           mac,
                           (dhcpServerIP+k),
                           NULL);

        if((rv = ops->add(table_priv, key, value, &entry_priv)) != INDIGO_ERROR_NONE) {
            printf("Test Add table incorret Vlan range %u, rv=%u\n", k, rv);
        }
    }

    vlan_no = dhcpr_table_get_vlan_entry_count();
    vr_ip_no = dhcpr_table_get_virtual_router_ip_entry_count();
    AIM_TRUE_OR_DIE(vlan_no  == num_of_vlan+1, "vlan=%u", vlan_no);
    AIM_TRUE_OR_DIE(vr_ip_no == num_of_vlan+1, "vr_ip_no=%u", vr_ip_no);

    printf("TEST:2 modify all\n");
    /* Modify 1/4:
     * --Same virtual Router
     * --No circuit
     * */
    for (k = 0; k < num_of_vlan/4 ; k++) {
        dhc_relay = dhcpr_get_dhcpr_entry_from_vlan_table(k);
        AIM_TRUE_OR_DIE(dhc_relay);
        key = make_key(k);
        value = make_value((virtualRouterIP+k),
                           mac,
                           (dhcpServerIP+k),
                           NULL);

        if((rv = ops->modify(table_priv, dhc_relay, key, value)) != INDIGO_ERROR_NONE) {
            printf("Error Add table %u, rv=%u", k, rv);
            exit(1);
        }
    }
    /* Modify 1/4-2/4:
     * --Diff virtual Router
     * --No circuit
     * */
    for (k = num_of_vlan/4; k < num_of_vlan/2; k++) {
        dhc_relay = dhcpr_get_dhcpr_entry_from_vlan_table(k);
        AIM_TRUE_OR_DIE(dhc_relay);
        key = make_key(k);
        value = make_value((virtualRouterIP+k+num_of_vlan),
                           mac,
                           (dhcpServerIP+k),
                           NULL);

        if((rv = ops->modify(table_priv, dhc_relay, key, value)) != INDIGO_ERROR_NONE) {
            printf("Error Add table %u, rv=%u", k, rv);
            exit(1);
        }
    }

    /* Modify 2/4-3/4
     * -- Same virtual router
     * -- Add circuit
     * */
    for (k = num_of_vlan/2; k<= 3*num_of_vlan/4 ; k++) {
        dhc_relay = dhcpr_get_dhcpr_entry_from_vlan_table(k);
        AIM_TRUE_OR_DIE(dhc_relay);

        cir_id.bytes = sizeof(cir_value[k]);
        cir_id.data  = (uint8_t*)&cir_value[k];
        key = make_key(k);
        value = make_value((virtualRouterIP+k),
                           mac,
                           (dhcpServerIP+k),
                           &cir_id);

        if((rv = ops->modify(table_priv, dhc_relay, key, value)) != INDIGO_ERROR_NONE) {
            printf("Error Add table %u, rv=%u", k, rv);
            exit(1);
        }
    }

    /* Modify 2/4-3/4
     * -- Diff virtual router
     * -- Add circuit
     * */
    for (k = 3*num_of_vlan/4; k<= num_of_vlan ; k++) {
        dhc_relay = dhcpr_get_dhcpr_entry_from_vlan_table(k);
        AIM_TRUE_OR_DIE(dhc_relay);
        cir_id.bytes = sizeof(cir_value[k]);
        cir_id.data  = (uint8_t*)&cir_value[k];
        key = make_key(k);
        value = make_value((virtualRouterIP+k+num_of_vlan),
                           mac,
                           (dhcpServerIP+k),
                           &cir_id);

        if((rv = ops->modify(table_priv, dhc_relay, key, value)) != INDIGO_ERROR_NONE) {
            printf("Error Add table %u, rv=%u", k, rv);
            exit(1);
        }
    }

    vlan_no = dhcpr_table_get_vlan_entry_count();
    vr_ip_no = dhcpr_table_get_virtual_router_ip_entry_count();
    AIM_TRUE_OR_DIE(vlan_no  == num_of_vlan+1, "vlan=%u", vlan_no);
    AIM_TRUE_OR_DIE(vr_ip_no == num_of_vlan+1, "vr_ip_no=%u", vr_ip_no);

    printf("TEST:3 delete all\n");
    for (k = 0; k<= num_of_vlan; k++) {
        dhc_relay = dhcpr_get_dhcpr_entry_from_vlan_table(k);
        AIM_TRUE_OR_DIE(dhc_relay);
        key = make_key(k);
        ops->del(table_priv, dhc_relay, key);
    }
    /* Delete all */
    vlan_no = dhcpr_table_get_vlan_entry_count();
    vr_ip_no = dhcpr_table_get_virtual_router_ip_entry_count();
    AIM_TRUE_OR_DIE(vlan_no == 0);
    AIM_TRUE_OR_DIE(vr_ip_no == 0);

    return 1;
}
Exemple #17
0
/* Dummy for compiler */
void
indigo_core_gentable_unregister (indigo_core_gentable_t *gentable)
{
    AIM_TRUE_OR_DIE(gentable == (void *)1);
}
Exemple #18
0
int
test_discovery_pkt_in(int port_no, int indigo_ret_expected)
{

#define OUT_PKT_BUF_SIZE 1500
    uint8_t  buf[OUT_PKT_BUF_SIZE];

    int rv = 0;
    of_packet_in_t *obj = 0;
    ppe_packet_t    ppep;
    of_octets_t data = {
        .bytes = sizeof(Dhcp_discovery) //346 bytes (342 + 4byteVLAN
    };

    /* Timeout due to re-register the timer */
    printf("\n\n*******************************\n");
    printf("TEST 1 DHCP Discovery: PKT_IN on port:%d\nExpect Option Added\n", port_no);
    printf("pkt_in bytes = %d\n", data.bytes);
    printf("*******************************\n");

    /* Set up GOLDEN Expected pkt*/
    AIM_TRUE_OR_DIE(sizeof(Dhcp_discovery_expected) <= OUT_PKT_BUF_SIZE);
    convert_chars_to_bytes(Dhcp_discovery_expected, 
                           Dhcp_discovery_expected_hex_stream, 
                           sizeof(Dhcp_discovery_expected));
    
    /* Setup discovery pkt */
    AIM_TRUE_OR_DIE(sizeof(Dhcp_discovery) <= OUT_PKT_BUF_SIZE);
    convert_chars_to_bytes(Dhcp_discovery, Dhcp_discovery_hex_stream, sizeof(Dhcp_discovery));
    memcpy(buf, Dhcp_discovery, sizeof(Dhcp_discovery));
    data.data = buf;

    obj = of_packet_in_new(OF_VERSION_1_0);
    AIM_TRUE_OR_DIE(obj);

    of_packet_in_reason_set(obj, OF_PACKET_IN_REASON_BSN_DHCP);
    of_packet_in_in_port_set(obj,port_no);

    if(of_packet_in_data_set(obj, &data) < 0) {
        AIM_TRUE_OR_DIE(obj);
    }

    /* Dump pkt in obj */
//    of_object_dump((loci_writer_f)aim_printf, &aim_pvs_stdout, obj);

    ppe_packet_init(&ppep, data.data, data.bytes);
	if (ppe_parse(&ppep) < 0) {
	    printf("\nERROR: Packet parsing failed. packet=%p, len=%u", data.data, data.bytes);
	}

    /* Dump up to DHCP hdr */
//    ppe_packet_dump(&ppep,&aim_pvs_stdout);
//    parse_dhcp_options(&ppep, data.bytes, 0, 0);

    /* Handle packet */
    rv = dhcpra_handle_pkt (obj);

    AIM_TRUE_OR_DIE(rv == indigo_ret_expected);

    of_packet_in_delete(obj);
    return rv;
}

int
test_offer_pkt_in(int port_no)
{

#define OUT_PKT_BUF_SIZE 1500
    uint8_t  buf[OUT_PKT_BUF_SIZE];

    int rv = 0;
    of_packet_in_t *obj;
    ppe_packet_t    ppep;
    of_octets_t data = {
        .bytes = sizeof(Dhcp_offer) //354 (342 + 4byte VLAN + 8bytes CirID)
    };

    printf("\n\n*******************************\n"
           "TEST 2 DHCP OFFER: PKT_IN on port:%d\nExpect Option Removed\n", port_no);
    printf("pkt_in bytes = %d\n", data.bytes);
    printf("*******************************\n\n");

     /* Set up GOLDEN Expected pkt*/
    //printf("Expected Offer pkt:\n");
    AIM_TRUE_OR_DIE(sizeof(Dhcp_offer_expected) <= OUT_PKT_BUF_SIZE);
    convert_chars_to_bytes(Dhcp_offer_expected, 
                           Dhcp_offer_expected_hex_stream, 
                           sizeof(Dhcp_offer_expected));

    /* Setup offer pkt */
    //printf("Offer pkt:\n");
    AIM_TRUE_OR_DIE(sizeof(Dhcp_offer) <= OUT_PKT_BUF_SIZE);
    convert_chars_to_bytes(Dhcp_offer,  Dhcp_offer_hex_stream, sizeof(Dhcp_offer));
    memcpy(buf, Dhcp_offer, sizeof(Dhcp_offer));
    data.data = buf;

    obj = of_packet_in_new(OF_VERSION_1_0);
    AIM_TRUE_OR_DIE(obj);
    of_packet_in_in_port_set(obj,port_no);

    of_packet_in_reason_set(obj, OF_PACKET_IN_REASON_BSN_DHCP);
    if(of_packet_in_data_set(obj, &data) < 0) {
        AIM_TRUE_OR_DIE(obj);
    }

    /* Dump pkt in obj */
    //of_object_dump((loci_writer_f)aim_printf, &aim_pvs_stdout, obj);
    ppe_packet_init(&ppep, data.data, data.bytes);
	if (ppe_parse(&ppep) < 0) {
	    printf("\nERROR: Packet parsing failed. packet=%p, len=%u", data.data, data.bytes);
	}

    /* Dump up to DHCP hdr */
    //ppe_packet_dump(&ppep,&aim_pvs_stdout);
    //parse_dhcp_options(&ppep, data.bytes, 0, 0);

    /* Handle packet */
    rv = dhcpra_handle_pkt (obj);

    if (rv == INDIGO_CORE_LISTENER_RESULT_PASS) {
        printf("\nError: NOT DHCP packet-in\n");
    } else if (rv == INDIGO_CORE_LISTENER_RESULT_DROP)
        printf("\nIS DHCP packet-in\n");
    else
        printf("\nError: Unsupport packet-in\n");

    of_packet_in_delete(obj);
    return rv;
}


int aim_main(int argc, char* argv[])
{
    printf("dhcpra Utest Is Empty\n");
    dhcpra_config_show(&aim_pvs_stdout);
    dhcpra_system_init();

    printf("\n*********\n0. PRE-TEST TABLE\n********\n");
    test_pass[0] = fill_all_vlan_dhcpr_table_test();

    printf("\n*********\nI. TEST PASS AFTER ADD and MOD\n********\n");
    add_entry_to_dhcpr_table();
    mod_entry_to_dhcpr_table();

    //Port 1: Correct setup, packet process
    //Driver will take care of sending L2_SRC_MISSED to controller
    test_discovery_pkt_in(1, INDIGO_CORE_LISTENER_RESULT_DROP);
    test_offer_pkt_in(1);

    printf("\n\nSUMMARY:\nDISCOV:\t%s\n", dhcp_pkt_matched[0] ? "PASSED" : "FAILED");
    printf("OFFER:\t%s\n", dhcp_pkt_matched[1] ? "PASSED" : "FAILED");
    test_pass[1] = dhcp_pkt_matched[0];
    test_pass[2] = dhcp_pkt_matched[1];

    printf("\n*********\nII. TEST FAILED AFTER DELETE\n********\n");
    dhcp_pkt_matched[0] = 0;
    dhcp_pkt_matched[1] = 0;
    del_entry_to_dhcpr_table();

    //Incorrect VLAN pass packet
    test_discovery_pkt_in(1, INDIGO_CORE_LISTENER_RESULT_PASS);
    test_offer_pkt_in(1);
    printf("\n\nSUMMARY:\nDISCOV:\t%s\n", dhcp_pkt_matched[0] ? "PASSED" : "FAILED");
    printf("OFFER:\t%s\n", dhcp_pkt_matched[1] ? "PASSED" : "FAILED");
    test_pass[3] = !dhcp_pkt_matched[0];
    test_pass[4] = !dhcp_pkt_matched[1];

    printf("\n\n*****SUMMARY ALL 3 TESTS*****\n");
    printf("TEST DHCP TABLE: %s\n", test_pass[0] ? "PASSED" : "FAILED");
    printf("TEST DISCOVER with valid table: %s\n", test_pass[1] ? "PASSED" : "FAILED");
    printf("TEST OFFER with valid table: %s\n",    test_pass[2] ? "PASSED" : "FAILED");
    printf("TEST DISCOVER with in valid table: %s\n", test_pass[3] ? "PASSED" : "FAILED");
    printf("TEST OFFER with in valid table: %s\n",    test_pass[4] ? "PASSED" : "FAILED");

    return 0;
}
static int
test_queue_desc_stats(void)
{
    struct ind_core_port *handle1, *handle2;
    indigo_core_port_register(1, &handle1);
    indigo_core_port_register(2, &handle2);

    struct ind_core_queue *queue1_3, *queue1_4, *queue2_3, *queue2_4;
    indigo_core_queue_register(1, 3, &queue1_3);
    indigo_core_queue_register(1, 4, &queue1_4);
    indigo_core_queue_register(2, 3, &queue2_3);
    indigo_core_queue_register(2, 4, &queue2_4);

    /* Request for OFPP_ANY, OF_QUEUE_ALL */
    memset(port_counters, 0, sizeof(port_counters));
    of_queue_desc_stats_request_t *obj = of_queue_desc_stats_request_new(OF_VERSION_1_4);
    of_queue_desc_stats_request_port_no_set(obj, OF_PORT_DEST_WILDCARD);
    of_queue_desc_stats_request_queue_id_set(obj, OF_QUEUE_ALL);
    handle_message(obj);
    do_barrier();

    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[3] == 1);
    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[4] == 1);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[3] == 1);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[4] == 1);

    /* Request for a single port, OF_QUEUE_ALL */
    memset(port_counters, 0, sizeof(port_counters));
    obj = of_queue_desc_stats_request_new(OF_VERSION_1_4);
    of_queue_desc_stats_request_port_no_set(obj, 2);
    of_queue_desc_stats_request_queue_id_set(obj, OF_QUEUE_ALL);
    handle_message(obj);
    do_barrier();

    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[3] == 0);
    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[4] == 0);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[3] == 1);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[4] == 1);

    /* Request for OFPP_ANY, a single queue */
    memset(port_counters, 0, sizeof(port_counters));
    obj = of_queue_desc_stats_request_new(OF_VERSION_1_4);
    of_queue_desc_stats_request_port_no_set(obj, OF_PORT_DEST_WILDCARD);
    of_queue_desc_stats_request_queue_id_set(obj, 4);
    handle_message(obj);
    do_barrier();

    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[3] == 0);
    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[4] == 1);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[3] == 0);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[4] == 1);

    /* Request for a single port and queue */
    memset(port_counters, 0, sizeof(port_counters));
    obj = of_queue_desc_stats_request_new(OF_VERSION_1_4);
    of_queue_desc_stats_request_port_no_set(obj, 2);
    of_queue_desc_stats_request_queue_id_set(obj, 4);
    handle_message(obj);
    do_barrier();

    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[3] == 0);
    AIM_TRUE_OR_DIE(port_counters[1].queue_desc_stats[4] == 0);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[3] == 0);
    AIM_TRUE_OR_DIE(port_counters[2].queue_desc_stats[4] == 1);

    indigo_core_queue_unregister(queue1_3);
    indigo_core_queue_unregister(queue1_4);
    indigo_core_queue_unregister(queue2_3);
    indigo_core_queue_unregister(queue2_4);
    indigo_core_port_unregister(handle1);
    indigo_core_port_unregister(handle2);

    return TEST_PASS;
}
Exemple #20
0
static int
os_sem_take_timeout_efd__(os_sem_t sem, uint64_t usecs)
{
    AIM_TRUE_OR_DIE(USES_EFD(sem), "timeout_efd__ called when efd is not valid.");

    /** poll() with timeout (in ms) */
    struct pollfd fds;

    fds.fd = sem->efd;
    fds.events = POLLIN;
    fds.revents = 0;

    uint64_t t_start = os_time_monotonic();
    int timeout_ms;

    if(usecs == 0) {
        /* Infinite timeout value when calling poll() */
        timeout_ms = -1;
    }
    else {
        timeout_ms = usecs / 1000;
    }

    for(;;) {

        int rv = poll(&fds, 1, timeout_ms);

        if(rv == 0) {
            /* Timed out */
            return -1;
        }
        if(rv == 1) {
            if(fds.revents & POLLIN) {
                /* Descriptor Ready */
                uint64_t v;
                if(eventfd_read(sem->efd, &v) == 0) {
                    /* Acquired. */
                    return 0;
                }
                else {
                    /**
                     * Acquired by someone else.
                     * Retry handled along with EINTR below.
                     */
                }
            }
        }
        if(rv == 1 || errno == EINTR) {
            /*
             * Calculate remaining timeout (if necessary) and retry.
             */
            if(timeout_ms != -1) {
                uint64_t now = os_time_monotonic();
                if( (now - t_start) >= usecs ) {
                    /* Total timeout has elapsed */
                    return -1;
                }
                else {
                    /* Remaining time to wait. */
                    timeout_ms = (usecs - (now - t_start) + 999)/1000;
                }
            }
            continue;
        }
        else {
            AIM_DIE("Unexpected return value from poll(): %s", strerror(errno));
        }
    }
}
/*
 * Register a sensor
 * Caller must make sure that 1 sensor registered only once
 * If it calls this twice, it will get 2 oid entries
 * for the same sensor
 *
 * We want to keep this snmp code as simple as possible
 */
static int
onlp_snmp_sensor_reg__(int sensor_type,
                       onlp_snmp_sensor_t *sensor)
{
    oid otemp[] = { ONLP_SNMP_SENSOR_TEMP_OID };
    oid ofan[]  = { ONLP_SNMP_SENSOR_FAN_OID };
    oid opsu[]  = { ONLP_SNMP_SENSOR_PSU_OID };
    oid oled[]  = { ONLP_SNMP_SENSOR_LED_OID };
    oid omisc[] = { ONLP_SNMP_SENSOR_MISC_OID };
    oid *o;
    u_long o_len;
    int ret = MIB_REGISTRATION_FAILED;

    onlp_snmp_sensor_ctrl_t *ss_type = get_sensor_ctrl__(sensor_type);

    /* We start with Base 1 */
    AIM_TRUE_OR_DIE(onlp_snmp_sensor_type_valid(sensor_type));
    AIM_TRUE_OR_DIE(sensor);
    AIM_TRUE_OR_DIE(ss_type);

    switch(sensor_type)
        {
        case ONLP_SNMP_SENSOR_TYPE_TEMP:
            o = otemp;
            o_len = OID_LENGTH(otemp);

            /* Not init yet, init oid table */
            if (!ss_type->handlers) {
                ss_type->handler_cnt = sizeof(temp_handler_fn__) / sizeof(temp_handler_fn__[0]);
                ss_type->handlers    = temp_handler_fn__;
                snprintf(ss_type->name, sizeof(ss_type->name), "%s", "temp_table");
            }
            break;

        case ONLP_SNMP_SENSOR_TYPE_FAN:
            o = ofan;
            o_len = OID_LENGTH(ofan);

            /* Not init yet, init oid table */
            if (!ss_type->handlers) {
                ss_type->handler_cnt = sizeof(fan_handler_fn__) / sizeof(fan_handler_fn__[0]);
                ss_type->handlers    = fan_handler_fn__;
                snprintf(ss_type->name, sizeof(ss_type->name), "%s", "fan_table");
            }
            break;

        case ONLP_SNMP_SENSOR_TYPE_PSU:
            o = opsu;
            o_len = OID_LENGTH(opsu);

            /* Not init yet, init oid table */
            if (!ss_type->handlers) {
                ss_type->handler_cnt = sizeof(psu_handler_fn__) / sizeof(psu_handler_fn__[0]);
                ss_type->handlers    = psu_handler_fn__;
                snprintf(ss_type->name, sizeof(ss_type->name), "%s", "psu_table");

            }
            break;

        case ONLP_SNMP_SENSOR_TYPE_LED:
            o = oled;
            o_len = OID_LENGTH(oled);

            /* Not init yet, init oid table */
            if (!ss_type->handlers) {
                ss_type->handler_cnt = sizeof(led_handler_fn__) / sizeof(led_handler_fn__[0]);
                ss_type->handlers    = led_handler_fn__;
                snprintf(ss_type->name, sizeof(ss_type->name), "%s", "led_table");
            }
            break;

        case ONLP_SNMP_SENSOR_TYPE_MISC:
            o = omisc;
            o_len = OID_LENGTH(omisc);

            /* Not init yet, init oid table */
            if (!ss_type->handlers) {
                ss_type->handler_cnt = sizeof(misc_handler_fn__) / sizeof(misc_handler_fn__[0]);
                ss_type->handlers    = misc_handler_fn__;
                snprintf(ss_type->name, sizeof(ss_type->name), "%s", "misc_table");
            }
            break;

        default:
            AIM_DIE("Invalid sensor value.");
            break;
    }

    /*
     * sensor_cnt original is 0
     * When sensor_cnt == ONLP_SNMP_CONFIG_DEV_MAX_INDEX
     * We stop adding
     */
    if (ss_type->sensor_cnt < ONLP_SNMP_CONFIG_DEV_MAX_INDEX) {
        /* Device index equal to ss_type->sensor_cnt */
        ss_type->sensor_cnt++;

        /* This entry must be null */
        AIM_TRUE_OR_DIE(!ss_type->sensor_list[ss_type->sensor_cnt]);

        snmp_log(LOG_INFO, "init type=%d, index=%d, id=%d",
                 sensor_type, ss_type->sensor_cnt, sensor->sensor_id);

        onlp_snmp_sensor_t *ss = AIM_MALLOC(sizeof(onlp_snmp_sensor_t));
        AIM_TRUE_OR_DIE(ss);
        AIM_MEMCPY(ss, sensor, sizeof(*sensor));
        ss->sensor_type = sensor_type;
        ss->info_valid = 0;
        ss->last_update_time = 0;

        /* Assign sensor to the list */
        ss_type->sensor_list[ss_type->sensor_cnt] = ss;

    } else {
        snmp_log(LOG_ALERT,
                 "Failed to register sensor type=%d id=%d, resource limited",
                 sensor_type, sensor->sensor_id);
        return ret;
    }

    AIM_TRUE_OR_DIE(o_len == ONLP_SNMP_SENSOR_OID_LENGTH,
                    "invalid oid length=%d", o_len);

    ret = reg_snmp_sensor_helper__(sensor_type, o, o_len,
                                   ss_type->sensor_cnt);
    if (ret) {
        snmp_log(LOG_ALERT,
                 "Failed to register sensor type=%d id=%d, MIB_ERROR=%d",
                 sensor_type, sensor->sensor_id, ret);
    }

    return ret;
}
Exemple #22
0
void
sem_test_multiple(uint32_t flags, int giving_threads, int taking_threads)
{
    int i;

    int thread_count = giving_threads + taking_threads;
    sem_test_t* tests = aim_zmalloc(sizeof(*tests)*thread_count);

    aim_sem_t take = aim_sem_create_flags(0, flags);
    aim_sem_t give = aim_sem_create_flags(0, flags);
    int acquired = 0;
    sem_test_t* t = tests;

    /*
     * These threads wait on a semaphore timeout
     * that will always expire. Timeout in [10000,100000].
     *
     * When the first timeout expires they give a different sem.
     */
    for(i = 0; i < giving_threads; i++, t++) {
        t->take = take;
        t->give = give;
        sprintf(t->name, "(1:%.4d)", i);
        t->timeout = ( (random() % 10) + 1 ) * 100000;
        t->timeout_required = 1;
        t->acquired = &acquired;
        pthread_create(&t->thread, NULL, sem_test_thread__, t);
    }

    /*
     * These threads wait on the semaphore given at the end
     * of the waiting period for the first set of threads.
     *
     * Some will timeout, some will acquire.
     *
     * Their timeouts are all in [2000000, 3000000].
     */
    for(i = 0; i < taking_threads; i++, t++) {
        t->take = give;
        t->give = NULL;
        sprintf(t->name, "(2:%.4d)", i);
        t->timeout = 2000000 + (( (random() % 10) + 1 ) * 100000);
        t->give = 0;
        t->timeout_required = 0;
        t->acquired = &acquired;
        pthread_create(&t->thread, NULL, sem_test_thread__, t);
    }

    for(i = 0; i < thread_count; i++) {
        void* rv;
        pthread_join(tests[i].thread, &rv);
    }

    /*
     * The acquisition count should always be equal to the number
     * of giving threads when (giving_threads <= taking_threads).
     */
    printf("Acquisition count: %d\n", acquired);
    AIM_TRUE_OR_DIE(acquired == giving_threads, "Failed");

    aim_free(give);
    aim_free(take);
    aim_free(tests);
}
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);
}