/* * Add or modify flow table entry. * * When modifying, the stats can be optionally cleared */ static void flow_cmd_new(struct dpdk_flow_message *request) { struct dpdk_message reply = {0}; int32_t pos = 0; pos = rte_hash_lookup(handle, &request->key); if (pos < 0) { if (request->flags & FLAG_CREATE) { pos = rte_hash_add_key(handle, &request->key); flow_table_add_flow(pos, &request->key, request->action, true); reply.type = 0; } else { reply.type = ENOENT; } } else { if (request->flags & FLAG_REPLACE) { /* Retrieve flow stats*/ flow_table_get_flow(pos, NULL, NULL, &request->stats); /* Depending on the value of request->clear we will either update * or keep the same stats */ flow_table_add_flow(pos, &request->key, request->action, request->clear); reply.type = 0; } else { reply.type = EEXIST; } } reply.flow_msg = *request; send_reply_to_vswitchd(&reply); }
static const struct bundle_cfg *server_accept(struct task_gen_server *task, struct new_tuple *nt) { int ret = rte_hash_lookup(task->listen_hash, nt); if (ret < 0) return NULL; else return task->listen_entries[ret]; }
sflow_socket_t* sflow_socket_lookup(sflow_key_t* key) { sflow_key_dump("find socket for key", key); rte_rwlock_read_lock(&sflow_hash_lock); int32_t socket_id = rte_hash_lookup(sflow_hash, key); rte_rwlock_read_unlock(&sflow_hash_lock); sflow_socket_t* socket = ((int32_t) socket_id) < 0 ? NULL : sflow_sockets[socket_id]; if (socket) { RTE_LOG(DEBUG, L3L4, "found socket at id: %u\n", socket_id); } return socket; }
/* * Dump all flows. * * The message that is received contains the key for the previously dumped * flow entry. If the key is zero then we are dumping the first entry. We * reply with EOF when we have dumped all flows * */ static void flow_cmd_dump(struct dpdk_flow_message *request) { struct dpdk_message reply = {0}; struct flow_key empty = {0}; int32_t pos = 0; if (!memcmp(&request->key, &empty, sizeof(request->key))) { /* * if flow is empty, it is first call of dump(), * and start searching from the first rule */ pos = 0; } else { /* last dumped flow */ pos = rte_hash_lookup(handle, &request->key); if (pos < 0) { /* send error reply - the flow must be in the flow table */ reply.type = ENOENT; goto out; } /* search starting from the next flow */ pos++; } /* find next using flow */ for(;pos < MAX_FLOWS && !flow_table->used[pos]; pos++) ; if (pos < MAX_FLOWS) { flow_table_get_flow(pos, &request->key, &request->action, &request->stats); reply.type = 0; } else { /* it was last flow, send message that no more flows here */ reply.type = EOF; } out: reply.flow_msg = *request; send_reply_to_vswitchd(&reply); }
/* * Return flow entry to vswitchd if it exists */ static void flow_cmd_get(struct dpdk_flow_message *request) { struct dpdk_message reply = {0}; int32_t pos = 0; pos = rte_hash_lookup(handle, &request->key); if (pos < 0) { reply.type = ENOENT; } else { flow_table_get_flow(pos, NULL, &request->action, &request->stats); reply.type = 0; } reply.flow_msg = *request; send_reply_to_vswitchd(&reply); }
/* * This function takes a packet and routes it as per the flow table. */ static void switch_packet(struct rte_mbuf *pkt, uint8_t in_port) { int pos = 0; struct dpdk_upcall info = {0}; flow_key_extract(pkt, in_port, &info.key); pos = rte_hash_lookup(handle, &info.key); if (pos < 0) { /* flow table miss, send unmatched packet to the daemon */ info.cmd = PACKET_CMD_MISS; send_packet_to_vswitchd(pkt, &info); } else { flow_table_update_stats(pos, pkt); action_execute(pos, pkt); } }
static int handle_gen_queued(struct task_gen_server *task) { uint8_t out[MAX_PKT_BURST]; struct bundle_ctx *conn; struct pkt_tuple pkt_tuple; struct l4_meta l4_meta; uint16_t j; uint16_t cancelled = 0; int ret; if (task->cur_mbufs_beg == task->cur_mbufs_end) { task->cur_mbufs_end = fqueue_get(task->fqueue, task->cur_mbufs, MAX_PKT_BURST); task->cur_mbufs_beg = 0; } uint16_t n_pkts = task->cur_mbufs_end - task->cur_mbufs_beg; struct rte_mbuf **mbufs = task->cur_mbufs + task->cur_mbufs_beg; j = task->cancelled; if (task->cancelled) { uint16_t pkt_len = mbuf_wire_size(mbufs[0]); if (token_time_take(&task->token_time, pkt_len) != 0) return -1; out[0] = task->out_saved; task->cancelled = 0; } /* Main proc loop */ for (; j < n_pkts; ++j) { if (parse_pkt(mbufs[j], &pkt_tuple, &l4_meta)) { plogdx_err(mbufs[j], "Unknown packet, parsing failed\n"); out[j] = OUT_DISCARD; } conn = NULL; ret = rte_hash_lookup(task->bundle_ctx_pool.hash, (const void *)&pkt_tuple); if (ret >= 0) conn = task->bundle_ctx_pool.hash_entries[ret]; else { /* If not part of existing connection, try to create a connection */ struct new_tuple nt; nt.dst_addr = pkt_tuple.dst_addr; nt.proto_id = pkt_tuple.proto_id; nt.dst_port = pkt_tuple.dst_port; rte_memcpy(nt.l2_types, pkt_tuple.l2_types, sizeof(nt.l2_types)); const struct bundle_cfg *n; if (NULL != (n = server_accept(task, &nt))) { conn = bundle_ctx_pool_get(&task->bundle_ctx_pool); if (!conn) { out[j] = OUT_DISCARD; plogx_err("No more free bundles to accept new connection\n"); continue; } ret = rte_hash_add_key(task->bundle_ctx_pool.hash, (const void *)&pkt_tuple); if (ret < 0) { out[j] = OUT_DISCARD; bundle_ctx_pool_put(&task->bundle_ctx_pool, conn); plog_err("Adding key failed while trying to accept connection\n"); continue; } task->bundle_ctx_pool.hash_entries[ret] = conn; bundle_init_w_cfg(conn, n, task->heap, PEER_SERVER, &task->seed); conn->tuple = pkt_tuple; if (conn->ctx.stream_cfg->proto == IPPROTO_TCP) task->l4_stats.tcp_created++; else task->l4_stats.udp_created++; } else { plog_err("Packet received for service that does not exist :\n" "source ip = %0x:%u\n" "dst ip = %0x:%u\n", pkt_tuple.src_addr, rte_bswap16(pkt_tuple.src_port), pkt_tuple.dst_addr, rte_bswap16(pkt_tuple.dst_port)); } } /* bundle contains either an active connection or a newly created connection. If it is NULL, then not listening. */ if (NULL != conn) { ret = bundle_proc_data(conn, mbufs[j], &l4_meta, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); out[j] = ret == 0? 0: OUT_HANDLED; if (ret == 0) { uint16_t pkt_len = mbuf_wire_size(mbufs[j]); if (token_time_take(&task->token_time, pkt_len) != 0) { task->out_saved = out[j]; task->cancelled = 1; task->base.tx_pkt(&task->base, mbufs, j, out); task->cur_mbufs_beg += j; return -1; } } } else { pkt_tuple_debug(&pkt_tuple); plogd_dbg(mbufs[j], NULL); out[j] = OUT_DISCARD; } } task->base.tx_pkt(&task->base, mbufs, j, out); task->cur_mbufs_beg += j; return 0; }
static int handle_gen_bulk_client(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) { struct task_gen_client *task = (struct task_gen_client *)tbase; uint8_t out[MAX_PKT_BURST] = {0}; struct bundle_ctx *conn; int ret; if (n_pkts) { for (int i = 0; i < n_pkts; ++i) { struct pkt_tuple pt; struct l4_meta l4_meta; if (parse_pkt(mbufs[i], &pt, &l4_meta)) { plogdx_err(mbufs[i], "Parsing failed\n"); out[i] = OUT_DISCARD; continue; } ret = rte_hash_lookup(task->bundle_ctx_pool.hash, (const void *)&pt); if (ret < 0) { plogx_dbg("Client: packet RX that does not belong to connection:" "Client = "IPv4_BYTES_FMT":%d, Server = "IPv4_BYTES_FMT":%d\n", IPv4_BYTES(((uint8_t*)&pt.dst_addr)), rte_bswap16(pt.dst_port), IPv4_BYTES(((uint8_t*)&pt.src_addr)), rte_bswap16(pt.src_port)); plogdx_dbg(mbufs[i], NULL); if (pt.proto_id == IPPROTO_TCP) { stream_tcp_create_rst(mbufs[i], &l4_meta, &pt); out[i] = 0; continue; } else { out[i] = OUT_DISCARD; continue; } } conn = task->bundle_ctx_pool.hash_entries[ret]; ret = bundle_proc_data(conn, mbufs[i], &l4_meta, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); out[i] = ret == 0? 0: OUT_HANDLED; } task->base.tx_pkt(&task->base, mbufs, n_pkts, out); } /* If there is at least one callback to handle, handle at most MAX_PKT_BURST */ if (heap_top_is_lower(task->heap, rte_rdtsc())) { if (0 != refill_mbufs(&task->n_new_mbufs, task->mempool, task->new_mbufs)) return 0; uint16_t n_called_back = 0; while (heap_top_is_lower(task->heap, rte_rdtsc()) && n_called_back < MAX_PKT_BURST) { conn = BUNDLE_CTX_UPCAST(heap_pop(task->heap)); /* handle packet TX (retransmit or delayed transmit) */ ret = bundle_proc_data(conn, task->new_mbufs[n_called_back], NULL, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); if (ret == 0) { out[n_called_back] = 0; n_called_back++; } } plogx_dbg("During callback, will send %d packets\n", n_called_back); task->base.tx_pkt(&task->base, task->new_mbufs, n_called_back, out); task->n_new_mbufs -= n_called_back; } uint32_t n_new = task->bundle_ctx_pool.n_free_bundles; n_new = n_new > MAX_PKT_BURST? MAX_PKT_BURST : n_new; uint64_t diff = (rte_rdtsc() - task->new_conn_last_tsc)/task->new_conn_cost; task->new_conn_last_tsc += diff * task->new_conn_cost; task->new_conn_tokens += diff; if (task->new_conn_tokens > 16) task->new_conn_tokens = 16; if (n_new > task->new_conn_tokens) n_new = task->new_conn_tokens; task->new_conn_tokens -= n_new; if (n_new == 0) return 0; if (0 != refill_mbufs(&task->n_new_mbufs, task->mempool, task->new_mbufs)) return 0; for (uint32_t i = 0; i < n_new; ++i) { struct bundle_ctx *bundle_ctx = bundle_ctx_pool_get_w_cfg(&task->bundle_ctx_pool); PROX_ASSERT(bundle_ctx); struct pkt_tuple *pt = &bundle_ctx->tuple; int n_retries = 0; do { /* Note that the actual packet sent will contain swapped addresses and ports (i.e. pkt.src <=> tuple.dst). The incoming packet will match this struct. */ bundle_init(bundle_ctx, task->heap, PEER_CLIENT, &task->seed); ret = rte_hash_lookup(task->bundle_ctx_pool.hash, (const void *)pt); if (ret >= 0) { if (n_retries++ == 1000) { plogx_err("Already tried 1K times\n"); } } } while (ret >= 0); ret = rte_hash_add_key(task->bundle_ctx_pool.hash, (const void *)pt); if (ret < 0) { plogx_err("Failed to add key ret = %d, n_free = %d\n", ret, task->bundle_ctx_pool.n_free_bundles); bundle_ctx_pool_put(&task->bundle_ctx_pool, bundle_ctx); pkt_tuple_debug2(pt); out[i] = OUT_DISCARD; continue; } task->bundle_ctx_pool.hash_entries[ret] = bundle_ctx; if (bundle_ctx->ctx.stream_cfg->proto == IPPROTO_TCP) task->l4_stats.tcp_created++; else task->l4_stats.udp_created++; task->l4_stats.bundles_created++; ret = bundle_proc_data(bundle_ctx, task->new_mbufs[i], NULL, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); out[i] = ret == 0? 0: OUT_HANDLED; } int ret2 = task->base.tx_pkt(&task->base, task->new_mbufs, n_new, out); task->n_new_mbufs -= n_new; return ret2; }
static void handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) { struct task_gen_server *task = (struct task_gen_server *)tbase; struct pkt_tuple pkt_tuple[MAX_PKT_BURST]; uint8_t out[MAX_PKT_BURST]; struct l4_meta l4_meta[MAX_PKT_BURST]; struct bundle_ctx *conn; int ret; for (uint16_t j = 0; j < n_pkts; ++j) { if (parse_pkt(mbufs[j], &pkt_tuple[j], &l4_meta[j])) plogdx_err(mbufs[j], "Unknown packet, parsing failed\n"); } /* Main proc loop */ for (uint16_t j = 0; j < n_pkts; ++j) { conn = NULL; ret = rte_hash_lookup(task->bundle_ctx_pool.hash, (const void *)&pkt_tuple[j]); if (ret >= 0) conn = task->bundle_ctx_pool.hash_entries[ret]; /* If not part of existing connection, try to create a connection */ if (NULL == conn) { struct new_tuple nt; nt.dst_addr = pkt_tuple[j].dst_addr; nt.proto_id = pkt_tuple[j].proto_id; nt.dst_port = pkt_tuple[j].dst_port; rte_memcpy(nt.l2_types, pkt_tuple[j].l2_types, sizeof(nt.l2_types)); const struct bundle_cfg *n; if (NULL != (n = server_accept(task, &nt))) { conn = bundle_ctx_pool_get(&task->bundle_ctx_pool); if (!conn) { out[j] = NO_PORT_AVAIL; plogx_err("No more free bundles to accept new connection\n"); continue; } ret = rte_hash_add_key(task->bundle_ctx_pool.hash, (const void *)&pkt_tuple[j]); if (ret < 0) { out[j] = NO_PORT_AVAIL; bundle_ctx_pool_put(&task->bundle_ctx_pool, conn); plog_err("Adding key failed while trying to accept connection\n"); continue; } task->bundle_ctx_pool.hash_entries[ret] = conn; bundle_init(conn, n, task->heap, PEER_SERVER, &task->seed); conn->tuple = pkt_tuple[j]; if (conn->ctx.stream_cfg->proto == IPPROTO_TCP) task->l4_stats.tcp_created++; else task->l4_stats.udp_created++; } } /* bundle contains either an active connection or a newly created connection. If it is NULL, then not listening. */ if (NULL != conn) { int ret = bundle_proc_data(conn, mbufs[j], &l4_meta[j], &task->bundle_ctx_pool, &task->seed, &task->l4_stats); out[j] = ret == 0? 0: NO_PORT_AVAIL; } else { plog_err("Packet received for service that does not exist\n"); pkt_tuple_debug(&pkt_tuple[j]); plogd_dbg(mbufs[j], NULL); out[j] = NO_PORT_AVAIL; } } conn = NULL; task->base.tx_pkt(&task->base, mbufs, n_pkts, out); if (!(task->heap->n_elems && rte_rdtsc() > heap_peek_prio(task->heap))) return ; if (task->n_new_mbufs < MAX_PKT_BURST) { if (rte_mempool_get_bulk(task->mempool, (void **)task->new_mbufs, MAX_PKT_BURST - task->n_new_mbufs) < 0) { return ; } for (uint32_t i = 0; i < MAX_PKT_BURST - task->n_new_mbufs; ++i) { init_mbuf_seg(task->new_mbufs[i]); } task->n_new_mbufs = MAX_PKT_BURST; } if (task->heap->n_elems && rte_rdtsc() > heap_peek_prio(task->heap)) { uint16_t n_called_back = 0; while (task->heap->n_elems && rte_rdtsc() > heap_peek_prio(task->heap) && n_called_back < MAX_PKT_BURST) { conn = BUNDLE_CTX_UPCAST(heap_pop(task->heap)); /* handle packet TX (retransmit or delayed transmit) */ ret = bundle_proc_data(conn, task->new_mbufs[n_called_back], NULL, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); if (ret == 0) { out[n_called_back] = 0; n_called_back++; } } task->base.tx_pkt(&task->base, task->new_mbufs, n_called_back, out); task->n_new_mbufs -= n_called_back; } }
static void handle_gen_bulk_client(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) { struct task_gen_client *task = (struct task_gen_client *)tbase; uint8_t out[MAX_PKT_BURST] = {0}; struct bundle_ctx *conn; int ret; if (n_pkts) { for (int i = 0; i < n_pkts; ++i) { struct pkt_tuple pt; struct l4_meta l4_meta; if (parse_pkt(mbufs[i], &pt, &l4_meta)) { plogdx_err(mbufs[i], "Parsing failed\n"); out[i] = NO_PORT_AVAIL; continue; } ret = rte_hash_lookup(task->bundle_ctx_pool.hash, (const void *)&pt); if (ret < 0) { plogx_dbg("Client: packet RX that does not belong to connection:" "Client = "IPv4_BYTES_FMT":%d, Server = "IPv4_BYTES_FMT":%d\n", IPv4_BYTES(((uint8_t*)&pt.dst_addr)), rte_bswap16(pt.dst_port), IPv4_BYTES(((uint8_t*)&pt.src_addr)), rte_bswap16(pt.src_port)); plogdx_dbg(mbufs[i], NULL); // if tcp, send RST /* pkt_tuple_debug2(&pt); */ out[i] = NO_PORT_AVAIL; continue; } conn = task->bundle_ctx_pool.hash_entries[ret]; ret = bundle_proc_data(conn, mbufs[i], &l4_meta, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); out[i] = ret == 0? 0: NO_PORT_AVAIL; } task->base.tx_pkt(&task->base, mbufs, n_pkts, out); } if (task->n_new_mbufs < MAX_PKT_BURST) { if (rte_mempool_get_bulk(task->mempool, (void **)task->new_mbufs, MAX_PKT_BURST - task->n_new_mbufs) < 0) { plogx_err("4Mempool alloc failed %d\n", MAX_PKT_BURST); return ; } for (uint32_t i = 0; i < MAX_PKT_BURST - task->n_new_mbufs; ++i) { init_mbuf_seg(task->new_mbufs[i]); } task->n_new_mbufs = MAX_PKT_BURST; } /* If there is at least one callback to handle, handle at most MAX_PKT_BURST */ if (task->heap->n_elems && rte_rdtsc() > heap_peek_prio(task->heap)) { uint16_t n_called_back = 0; while (task->heap->n_elems && rte_rdtsc() > heap_peek_prio(task->heap) && n_called_back < MAX_PKT_BURST) { conn = BUNDLE_CTX_UPCAST(heap_pop(task->heap)); /* handle packet TX (retransmit or delayed transmit) */ ret = bundle_proc_data(conn, task->new_mbufs[n_called_back], NULL, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); if (ret == 0) { out[n_called_back] = 0; n_called_back++; } } plogx_dbg("During callback, will send %d packets\n", n_called_back); task->base.tx_pkt(&task->base, task->new_mbufs, n_called_back, out); task->n_new_mbufs -= n_called_back; } int n_new = task->bundle_ctx_pool.n_free_bundles; n_new = n_new > MAX_PKT_BURST? MAX_PKT_BURST : n_new; if (n_new == 0) return ; if (task->n_new_mbufs < MAX_PKT_BURST) { if (rte_mempool_get_bulk(task->mempool, (void **)task->new_mbufs, MAX_PKT_BURST - task->n_new_mbufs) < 0) { plogx_err("4Mempool alloc failed %d\n", MAX_PKT_BURST); return ; } for (uint32_t i = 0; i < MAX_PKT_BURST - task->n_new_mbufs; ++i) { init_mbuf_seg(task->new_mbufs[i]); } task->n_new_mbufs = MAX_PKT_BURST; } for (int i = 0; i < n_new; ++i) { int32_t ret = cdf_sample(task->cdf, &task->seed); /* Select a new bundle_cfg according to imix */ struct bundle_cfg *bundle_cfg = &task->bundle_cfgs[ret]; struct bundle_ctx *bundle_ctx; bundle_ctx = bundle_ctx_pool_get(&task->bundle_ctx_pool); /* Should be an assert: */ if (!bundle_ctx) { plogx_err("No more available bundles\n"); exit(-1); } struct pkt_tuple *pt = &bundle_ctx->tuple; int n_retries = 0; do { /* Note that the actual packet sent will contain swapped addresses and ports (i.e. pkt.src <=> tuple.dst). The incoming packet will match this struct. */ bundle_init(bundle_ctx, bundle_cfg, task->heap, PEER_CLIENT, &task->seed); ret = rte_hash_lookup(task->bundle_ctx_pool.hash, (const void *)pt); if (n_retries == 1000) { plogx_err("Already tried 1K times\n"); } if (ret >= 0) { n_retries++; } } while (ret >= 0); ret = rte_hash_add_key(task->bundle_ctx_pool.hash, (const void *)pt); if (ret < 0) { plogx_err("Failed to add key ret = %d, n_free = %d\n", ret, task->bundle_ctx_pool.n_free_bundles); bundle_ctx_pool_put(&task->bundle_ctx_pool, bundle_ctx); pkt_tuple_debug2(pt); out[i] = NO_PORT_AVAIL; continue; } task->bundle_ctx_pool.hash_entries[ret] = bundle_ctx; if (bundle_ctx->ctx.stream_cfg->proto == IPPROTO_TCP) task->l4_stats.tcp_created++; else task->l4_stats.udp_created++; ret = bundle_proc_data(bundle_ctx, task->new_mbufs[i], NULL, &task->bundle_ctx_pool, &task->seed, &task->l4_stats); out[i] = ret == 0? 0: NO_PORT_AVAIL; } task->base.tx_pkt(&task->base, task->new_mbufs, n_new, out); task->n_new_mbufs -= n_new; }
int hash_table_lkup(const void *key) { return rte_hash_lookup(ht_hdl, key); }
static int timed_lookups(unsigned with_hash, unsigned with_data, unsigned table_index) { unsigned i, j; const uint64_t start_tsc = rte_rdtsc(); void *ret_data; void *expected_data; int32_t ret; for (i = 0; i < NUM_LOOKUPS/KEYS_TO_ADD; i++) { for (j = 0; j < KEYS_TO_ADD; j++) { if (with_hash && with_data) { ret = rte_hash_lookup_with_hash_data(h[table_index], (const void *) keys[j], signatures[j], &ret_data); if (ret < 0) { printf("Key number %u was not found\n", j); return -1; } expected_data = (void *) ((uintptr_t) signatures[j]); if (ret_data != expected_data) { printf("Data returned for key number %u is %p," " but should be %p\n", j, ret_data, expected_data); return -1; } } else if (with_hash && !with_data) { ret = rte_hash_lookup_with_hash(h[table_index], (const void *) keys[j], signatures[j]); if (ret < 0 || ret != positions[j]) { printf("Key looked up in %d, should be in %d\n", ret, positions[j]); return -1; } } else if (!with_hash && with_data) { ret = rte_hash_lookup_data(h[table_index], (const void *) keys[j], &ret_data); if (ret < 0) { printf("Key number %u was not found\n", j); return -1; } expected_data = (void *) ((uintptr_t) signatures[j]); if (ret_data != expected_data) { printf("Data returned for key number %u is %p," " but should be %p\n", j, ret_data, expected_data); return -1; } } else { ret = rte_hash_lookup(h[table_index], keys[j]); if (ret < 0 || ret != positions[j]) { printf("Key looked up in %d, should be in %d\n", ret, positions[j]); return -1; } } } } const uint64_t end_tsc = rte_rdtsc(); const uint64_t time_taken = end_tsc - start_tsc; cycles[table_index][LOOKUP][with_hash][with_data] = time_taken/NUM_LOOKUPS; return 0; }