static int timed_adds(unsigned with_hash, unsigned with_data, unsigned table_index) { unsigned i; const uint64_t start_tsc = rte_rdtsc(); void *data; int32_t ret; for (i = 0; i < KEYS_TO_ADD; i++) { data = (void *) ((uintptr_t) signatures[i]); if (with_hash && with_data) { ret = rte_hash_add_key_with_hash_data(h[table_index], (const void *) keys[i], signatures[i], data); if (ret < 0) { printf("Failed to add key number %u\n", ret); return -1; } } else if (with_hash && !with_data) { ret = rte_hash_add_key_with_hash(h[table_index], (const void *) keys[i], signatures[i]); if (ret >= 0) positions[i] = ret; else { printf("Failed to add key number %u\n", ret); return -1; } } else if (!with_hash && with_data) { ret = rte_hash_add_key_data(h[table_index], (const void *) keys[i], data); if (ret < 0) { printf("Failed to add key number %u\n", ret); return -1; } } else { ret = rte_hash_add_key(h[table_index], keys[i]); if (ret >= 0) positions[i] = ret; else { printf("Failed to add key number %u\n", ret); return -1; } } } const uint64_t end_tsc = rte_rdtsc(); const uint64_t time_taken = end_tsc - start_tsc; cycles[table_index][ADD][with_hash][with_data] = time_taken/KEYS_TO_ADD; return 0; }
int onvm_ft_add_key(struct onvm_ft* table, struct onvm_ft_ipv4_5tuple *key, char** data) { int32_t tbl_index; uint32_t softrss; softrss = onvm_softrss(key); tbl_index = rte_hash_add_key_with_hash(table->hash, (const void *)key, softrss); if (tbl_index >= 0) { *data = onvm_ft_get_data(table, tbl_index); } return tbl_index; }
/* Create a new flow table made of an rte_hash table and a fixed size * data array for storing values. Only supports IPv4 5-tuple lookups. */ struct onvm_ft* onvm_ft_create(int cnt, int entry_size) { struct rte_hash* hash; struct onvm_ft* ft; struct rte_hash_parameters ipv4_hash_params = { .name = NULL, .entries = cnt, .key_len = sizeof(struct onvm_ft_ipv4_5tuple), .hash_func = NULL, .hash_func_init_val = 0, }; char s[64]; /* create ipv4 hash table. use core number and cycle counter to get a unique name. */ ipv4_hash_params.name = s; ipv4_hash_params.socket_id = rte_socket_id(); snprintf(s, sizeof(s), "onvm_ft_%d-%"PRIu64, rte_lcore_id(), rte_get_tsc_cycles()); hash = rte_hash_create(&ipv4_hash_params); if (hash == NULL) { return NULL; } ft = (struct onvm_ft*)rte_calloc("table", 1, sizeof(struct onvm_ft), 0); if (ft == NULL) { rte_hash_free(hash); return NULL; } ft->hash = hash; ft->cnt = cnt; ft->entry_size = entry_size; /* Create data array for storing values */ ft->data = rte_calloc("entry", cnt, entry_size, 0); if (ft->data == NULL) { rte_hash_free(hash); rte_free(ft); return NULL; } return ft; } /* Add an entry in flow table and set data to point to the new value. Returns: index in the array on success -EPROTONOSUPPORT if packet is not ipv4. -EINVAL if the parameters are invalid. -ENOSPC if there is no space in the hash for this key. */ int onvm_ft_add_pkt(struct onvm_ft* table, struct rte_mbuf *pkt, char** data) { int32_t tbl_index; struct onvm_ft_ipv4_5tuple key; int err; err = onvm_ft_fill_key(&key, pkt); if (err < 0) { return err; } tbl_index = rte_hash_add_key_with_hash(table->hash, (const void *)&key, pkt->hash.rss); if (tbl_index >= 0) { *data = &table->data[tbl_index*table->entry_size]; } return tbl_index; }
/* * Looks for random keys which * ALL can fit in hash table (no errors) */ static int get_input_keys(unsigned with_pushes, unsigned table_index) { unsigned i, j; unsigned bucket_idx, incr, success = 1; uint8_t k = 0; int32_t ret; const uint32_t bucket_bitmask = NUM_BUCKETS - 1; /* Reset all arrays */ for (i = 0; i < MAX_ENTRIES; i++) slot_taken[i] = 0; for (i = 0; i < NUM_BUCKETS; i++) buckets[i] = 0; for (j = 0; j < hashtest_key_lens[table_index]; j++) keys[0][j] = 0; /* * Add only entries that are not duplicated and that fits in the table * (cannot store more than BUCKET_SIZE entries in a bucket). * Regardless a key has been added correctly or not (success), * the next one to try will be increased by 1. */ for (i = 0; i < KEYS_TO_ADD;) { incr = 0; if (i != 0) { keys[i][0] = ++k; /* Overflow, need to increment the next byte */ if (keys[i][0] == 0) incr = 1; for (j = 1; j < hashtest_key_lens[table_index]; j++) { /* Do not increase next byte */ if (incr == 0) if (success == 1) keys[i][j] = keys[i - 1][j]; else keys[i][j] = keys[i][j]; /* Increase next byte by one */ else { if (success == 1) keys[i][j] = keys[i-1][j] + 1; else keys[i][j] = keys[i][j] + 1; if (keys[i][j] == 0) incr = 1; else incr = 0; } } } success = 0; signatures[i] = rte_hash_hash(h[table_index], keys[i]); bucket_idx = signatures[i] & bucket_bitmask; /* * If we are not inserting keys in secondary location, * when bucket is full, do not try to insert the key */ if (with_pushes == 0) if (buckets[bucket_idx] == BUCKET_SIZE) continue; /* If key can be added, leave in successful key arrays "keys" */ ret = rte_hash_add_key_with_hash(h[table_index], keys[i], signatures[i]); if (ret >= 0) { /* If key is already added, ignore the entry and do not store */ if (slot_taken[ret]) continue; else { /* Store the returned position and mark slot as taken */ slot_taken[ret] = 1; positions[i] = ret; buckets[bucket_idx]++; success = 1; i++; } } } /* Reset the table, so we can measure the time to add all the entries */ rte_hash_free(h[table_index]); h[table_index] = rte_hash_create(&ut_params); return 0; }