From f6abc2e6a02557e82ad0d1e5440653bb8884ecc8 Mon Sep 17 00:00:00 2001 From: Patrice Buriez Date: Wed, 25 Oct 2017 20:30:34 +0200 Subject: [PATCH] Merge changes from PROX-v041 Change-Id: Ie6d4e7ce22c27967117a446626f5923643397812 Signed-off-by: Patrice Buriez --- VNFs/DPPD-PROX/Makefile | 8 +- VNFs/DPPD-PROX/README | 2 +- VNFs/DPPD-PROX/arp.h | 29 ++- VNFs/DPPD-PROX/cmd_parser.c | 47 +++-- VNFs/DPPD-PROX/commands.c | 22 ++- VNFs/DPPD-PROX/defaults.c | 2 + VNFs/DPPD-PROX/defaults.h | 1 + VNFs/DPPD-PROX/handle_arp.c | 4 +- VNFs/DPPD-PROX/handle_gen.c | 401 ++++++++++------------------------------- VNFs/DPPD-PROX/handle_gen.h | 1 - VNFs/DPPD-PROX/handle_impair.c | 58 +++++- VNFs/DPPD-PROX/handle_irq.c | 20 +- VNFs/DPPD-PROX/handle_master.c | 348 +++++++++++++++++++++++++++++++++++ VNFs/DPPD-PROX/handle_master.h | 43 +++++ VNFs/DPPD-PROX/handle_swap.c | 33 +--- VNFs/DPPD-PROX/handle_swap.h | 1 - VNFs/DPPD-PROX/input.c | 27 +++ VNFs/DPPD-PROX/input.h | 1 + VNFs/DPPD-PROX/lconf.c | 81 +++++++-- VNFs/DPPD-PROX/log.c | 2 +- VNFs/DPPD-PROX/main.c | 103 +++++++++-- VNFs/DPPD-PROX/msr.c | 2 +- VNFs/DPPD-PROX/packet_utils.c | 274 ++++++++++++++++++++++++++++ VNFs/DPPD-PROX/packet_utils.h | 54 ++++++ VNFs/DPPD-PROX/prox_args.c | 28 ++- VNFs/DPPD-PROX/prox_cfg.h | 1 + VNFs/DPPD-PROX/prox_cksum.c | 15 +- VNFs/DPPD-PROX/prox_port_cfg.c | 15 +- VNFs/DPPD-PROX/prox_port_cfg.h | 1 + VNFs/DPPD-PROX/run.c | 50 +++-- VNFs/DPPD-PROX/rx_pkt.c | 160 +++++++++++++--- VNFs/DPPD-PROX/rx_pkt.h | 8 + VNFs/DPPD-PROX/stats_core.c | 2 +- VNFs/DPPD-PROX/task_base.h | 12 +- VNFs/DPPD-PROX/task_init.c | 46 ++++- VNFs/DPPD-PROX/task_init.h | 7 +- VNFs/DPPD-PROX/tx_pkt.c | 225 +++++++++++++++++------ VNFs/DPPD-PROX/tx_pkt.h | 5 + VNFs/DPPD-PROX/version.h | 2 +- 39 files changed, 1630 insertions(+), 511 deletions(-) create mode 100644 VNFs/DPPD-PROX/handle_master.c create mode 100644 VNFs/DPPD-PROX/handle_master.h create mode 100644 VNFs/DPPD-PROX/packet_utils.c create mode 100644 VNFs/DPPD-PROX/packet_utils.h diff --git a/VNFs/DPPD-PROX/Makefile b/VNFs/DPPD-PROX/Makefile index e9a4211b..79bfdef3 100644 --- a/VNFs/DPPD-PROX/Makefile +++ b/VNFs/DPPD-PROX/Makefile @@ -78,8 +78,12 @@ endif endif endif +ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y) +LDLIBS += -lrte_pmd_ring -lrte_pmd_null -lrte_pmd_ixgbe -lrte_pmd_i40e -lrte_pmd_e1000 -lrte_pmd_virtio -lrte_pmd_vmxnet3_uio +endif + LD_TINFO = $(shell pkg-config --silence-errors --libs-only-l tinfo) -LDFLAGS += -lpcap $(LD_TINFO) $(LD_LUA) +LDFLAGS += -lm -lpcap $(LD_TINFO) $(LD_LUA) LDFLAGS += -lncurses -lncursesw -ledit PROX_STATS ?= y @@ -157,6 +161,8 @@ SRCS-y += handle_swap.c SRCS-y += handle_police.c SRCS-y += handle_acl.c SRCS-y += handle_gen.c +SRCS-y += handle_master.c +SRCS-y += packet_utils.c SRCS-y += handle_mirror.c SRCS-y += handle_genl4.c SRCS-y += handle_ipv6_tunnel.c diff --git a/VNFs/DPPD-PROX/README b/VNFs/DPPD-PROX/README index a09873cd..1cf857d5 100644 --- a/VNFs/DPPD-PROX/README +++ b/VNFs/DPPD-PROX/README @@ -24,7 +24,7 @@ finer grained network functions like QoS, Routing, load-balancing... Compiling and running this application -------------------------------------- -This application supports DPDK 16.04, 16.11, 16.11.1, 17.02 and 17.05. +This application supports DPDK 16.04, 16.11, 16.11.1, 17.02, 17.05 and 17.08. The following commands assume that the following variables have been set: export RTE_SDK=/path/to/dpdk diff --git a/VNFs/DPPD-PROX/arp.h b/VNFs/DPPD-PROX/arp.h index 279bdada..488008d7 100644 --- a/VNFs/DPPD-PROX/arp.h +++ b/VNFs/DPPD-PROX/arp.h @@ -18,6 +18,8 @@ #define _ARP_H_ #include +#include "etypes.h" +#include "mbuf_utils.h" #define ARP_REQUEST 0x100 #define ARP_REPLY 0x200 @@ -49,10 +51,13 @@ static int arp_is_gratuitous(struct ether_hdr_arp *hdr) return hdr->arp.data.spa == hdr->arp.data.tpa; } -static inline void prepare_arp_reply(struct ether_hdr_arp *hdr_arp, struct ether_addr *s_addr) +static inline void build_arp_reply(struct ether_hdr_arp *hdr_arp, struct ether_addr *s_addr) { uint32_t ip_source = hdr_arp->arp.data.spa; + memcpy(hdr_arp->ether_hdr.d_addr.addr_bytes, hdr_arp->ether_hdr.s_addr.addr_bytes, sizeof(struct ether_addr)); + memcpy(hdr_arp->ether_hdr.s_addr.addr_bytes, s_addr, sizeof(struct ether_addr)); + hdr_arp->arp.data.spa = hdr_arp->arp.data.tpa; hdr_arp->arp.data.tpa = ip_source; hdr_arp->arp.oper = 0x200; @@ -60,6 +65,28 @@ static inline void prepare_arp_reply(struct ether_hdr_arp *hdr_arp, struct ether memcpy(&hdr_arp->arp.data.sha, s_addr, sizeof(struct ether_addr)); } +static inline void build_arp_request(struct rte_mbuf *mbuf, struct ether_addr *src_mac, uint32_t ip_dst, uint32_t ip_src) +{ + struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *); + uint64_t mac_bcast = 0xFFFFFFFFFFFF; + rte_pktmbuf_pkt_len(mbuf) = 42; + rte_pktmbuf_data_len(mbuf) = 42; + init_mbuf_seg(mbuf); + + memcpy(&hdr_arp->ether_hdr.d_addr.addr_bytes, &mac_bcast, 6); + memcpy(&hdr_arp->ether_hdr.s_addr.addr_bytes, src_mac, 6); + hdr_arp->ether_hdr.ether_type = ETYPE_ARP; + hdr_arp->arp.htype = 0x100, + hdr_arp->arp.ptype = 0x0008; + hdr_arp->arp.hlen = 6; + hdr_arp->arp.plen = 4; + hdr_arp->arp.oper = 0x100; + hdr_arp->arp.data.spa = ip_src; + hdr_arp->arp.data.tpa = ip_dst; + memset(&hdr_arp->arp.data.tha, 0, sizeof(struct ether_addr)); + memcpy(&hdr_arp->arp.data.sha, src_mac, sizeof(struct ether_addr)); +} + static void create_mac(struct ether_hdr_arp *hdr, struct ether_addr *addr) { addr->addr_bytes[0] = 0x2; diff --git a/VNFs/DPPD-PROX/cmd_parser.c b/VNFs/DPPD-PROX/cmd_parser.c index 95688477..388e3620 100644 --- a/VNFs/DPPD-PROX/cmd_parser.c +++ b/VNFs/DPPD-PROX/cmd_parser.c @@ -51,6 +51,7 @@ #include "stats_latency.h" #include "handle_cgnat.h" #include "handle_impair.h" +#include "rx_pkt.h" static int core_task_is_valid(int lcore_id, int task_id) { @@ -235,6 +236,22 @@ static int parse_cmd_dump_rx(const char *str, struct input *input) if (cores_task_are_valid(lcores, task_id, nb_cores)) { for (unsigned int i = 0; i < nb_cores; i++) { + if (lcores[i] > RTE_MAX_LCORE) { + plog_warn("core_id too high, maximum allowed is: %u\n", RTE_MAX_LCORE); + return -1; + } else if (task_id >= lcore_cfg[lcores[i]].n_tasks_all) { + plog_warn("task_id too high, should be in [0, %u]\n", lcore_cfg[lcores[i]].n_tasks_all - 1); + return -1; + } else { + struct lcore_cfg *lconf = &lcore_cfg[lcores[i]]; + struct task_base *tbase = lconf->tasks_all[task_id]; + int prev_count = tbase->aux->rx_prev_count; + if (((prev_count) && (tbase->aux->rx_pkt_prev[prev_count - 1] == rx_pkt_dummy)) + || (tbase->rx_pkt == rx_pkt_dummy)) { + plog_warn("Unable to dump_rx as rx_pkt_dummy\n"); + return -1; + } + } cmd_dump(lcores[i], task_id, nb_packets, input, 1, 0); } } @@ -375,8 +392,9 @@ static int parse_cmd_set_probability(const char *str, struct input *input) if (cores_task_are_valid(lcores, task_id, nb_cores)) { for (unsigned int i = 0; i < nb_cores; i++) { lcore_id = lcores[i]; - if (!task_is_mode(lcore_id, task_id, "impair", "")) { + if ((!task_is_mode(lcore_id, task_id, "impair", "")) && (!task_is_mode(lcore_id, task_id, "impair", "l3"))){ plog_err("Core %u task %u is not impairing packets\n", lcore_id, task_id); + return -1; } struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; task_impair_set_proba(tbase, probability); @@ -399,8 +417,9 @@ static int parse_cmd_delay_us(const char *str, struct input *input) if (cores_task_are_valid(lcores, task_id, nb_cores)) { for (unsigned int i = 0; i < nb_cores; i++) { lcore_id = lcores[i]; - if (!task_is_mode(lcore_id, task_id, "impair", "")) { + if ((!task_is_mode(lcore_id, task_id, "impair", "")) && (!task_is_mode(lcore_id, task_id, "impair", "l3"))){ plog_err("Core %u task %u is not impairing packets\n", lcore_id, task_id); + return -1; } struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; task_impair_set_delay_us(tbase, delay_us, 0); @@ -423,8 +442,9 @@ static int parse_cmd_random_delay_us(const char *str, struct input *input) if (cores_task_are_valid(lcores, task_id, nb_cores)) { for (unsigned int i = 0; i < nb_cores; i++) { lcore_id = lcores[i]; - if (!task_is_mode(lcore_id, task_id, "impair", "")) { + if ((!task_is_mode(lcore_id, task_id, "impair", "")) && (!task_is_mode(lcore_id, task_id, "impair", "l3"))){ plog_err("Core %u task %u is not impairing packets\n", lcore_id, task_id); + return -1; } struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; task_impair_set_delay_us(tbase, 0, delay_us); @@ -832,14 +852,15 @@ static int parse_cmd_gateway_ip(const char *str, struct input *input) } for (i = 0; i < nb_cores; i++) { lcore_id = lcores[i]; - if ((!task_is_mode(lcore_id, task_id, "gen", "")) && (!task_is_mode(lcore_id, task_id, "gen", "l3"))) { - plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id); + + if (!task_is_sub_mode(lcore_id, task_id, "l3")) { + plog_err("Core %u task %u is not in l3 mode\n", lcore_id, task_id); } else { uint32_t gateway_ip = ((ip[3] & 0xFF) << 24) | ((ip[2] & 0xFF) << 16) | ((ip[1] & 0xFF) << 8) | ((ip[0] & 0xFF) << 0); struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; plog_info("Setting gateway ip to %s\n", str); - task_gen_set_gateway_ip(tbase, gateway_ip); + task_set_gateway_ip(tbase, gateway_ip); } } return 0; @@ -860,12 +881,16 @@ static int parse_cmd_local_ip(const char *str, struct input *input) } for (i = 0; i < nb_cores; i++) { lcore_id = lcores[i]; + struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; + uint32_t local_ip = ((ip[3] & 0xFF) << 24) | ((ip[2] & 0xFF) << 16) | ((ip[1] & 0xFF) << 8) | ((ip[0] & 0xFF) << 0); if (!task_is_mode(lcore_id, task_id, "arp", "local")) { - plog_err("Core %u task %u is not in arp mode\n", lcore_id, task_id); - } - else { - uint32_t local_ip = ((ip[3] & 0xFF) << 24) | ((ip[2] & 0xFF) << 16) | ((ip[1] & 0xFF) << 8) | ((ip[0] & 0xFF) << 0); - struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; + if (!task_is_sub_mode(lcore_id, task_id, "l3")) { + plog_err("Core %u task %u is not in l3 mode\n", lcore_id, task_id); + } else { + plog_info("Setting local ip to %s\n", str); + task_set_local_ip(tbase, local_ip); + } + } else { plog_info("Setting local ip to %s\n", str); task_arp_set_local_ip(tbase, local_ip); } diff --git a/VNFs/DPPD-PROX/commands.c b/VNFs/DPPD-PROX/commands.c index 93acc62a..adfb690a 100644 --- a/VNFs/DPPD-PROX/commands.c +++ b/VNFs/DPPD-PROX/commands.c @@ -101,10 +101,22 @@ static inline int wait_command_handled(struct lcore_cfg *lconf) } return 0; } + +static inline void start_l3(struct task_args *targ) +{ + if (!task_is_master(targ)) { + if ((targ->nb_txrings != 0) || (targ->nb_txports != 0)) { + if (targ->task_init->flag_features & TASK_FEATURE_L3) + task_start_l3(targ->tbase, targ); + } + } +} + void start_cores(uint32_t *cores, int count, int task_id) { int n_started_cores = 0; uint32_t started_cores[RTE_MAX_LCORE]; + struct task_args *targ; warn_inactive_cores(cores, count, "Can't start core"); @@ -112,7 +124,15 @@ void start_cores(uint32_t *cores, int count, int task_id) struct lcore_cfg *lconf = &lcore_cfg[cores[i]]; if (lconf->n_tasks_run != lconf->n_tasks_all) { - + if (task_id == -1) { + for (uint8_t tid = 0; tid < lconf->n_tasks_all; ++tid) { + targ = &lconf->targs[tid]; + start_l3(targ); + } + } else { + targ = &lconf->targs[task_id]; + start_l3(targ); + } lconf->msg.type = LCONF_MSG_START; lconf->msg.task_id = task_id; lconf_set_req(lconf); diff --git a/VNFs/DPPD-PROX/defaults.c b/VNFs/DPPD-PROX/defaults.c index eeb21b2d..6688e8c6 100644 --- a/VNFs/DPPD-PROX/defaults.c +++ b/VNFs/DPPD-PROX/defaults.c @@ -26,6 +26,7 @@ #include "prox_port_cfg.h" #include "etypes.h" #include "toeplitz.h" +#include "handle_master.h" #define TEN_GIGABIT 1250000000 #define QUEUE_SIZES 128 @@ -116,6 +117,7 @@ void set_global_defaults(__attribute__((unused)) struct prox_cfg *prox_cfg) void set_task_defaults(struct prox_cfg* prox_cfg, struct lcore_cfg* lcore_cfg_init) { prox_cfg->master = RTE_MAX_LCORE; + handle_ctrl_plane = NULL; for (uint32_t i = 0; i < RTE_DIM(prox_cfg->cpe_table_ports); ++i) { prox_cfg->cpe_table_ports[i] = -1; diff --git a/VNFs/DPPD-PROX/defaults.h b/VNFs/DPPD-PROX/defaults.h index 5fb31207..573cc9c5 100644 --- a/VNFs/DPPD-PROX/defaults.h +++ b/VNFs/DPPD-PROX/defaults.h @@ -28,6 +28,7 @@ void set_port_defaults(void); #define MAX_PKT_BURST 64 #define MAX_RING_BURST 64 +#define DUMP_PKT_LEN 128 #if MAX_RING_BURST < MAX_PKT_BURST #error MAX_RING_BURST < MAX_PKT_BURST diff --git a/VNFs/DPPD-PROX/handle_arp.c b/VNFs/DPPD-PROX/handle_arp.c index 106e19e5..767cee11 100644 --- a/VNFs/DPPD-PROX/handle_arp.c +++ b/VNFs/DPPD-PROX/handle_arp.c @@ -46,9 +46,7 @@ static void task_update_config(struct task_arp *task) static void handle_arp(struct task_arp *task, struct ether_hdr_arp *hdr, struct ether_addr *s_addr) { - prepare_arp_reply(hdr, s_addr); - memcpy(hdr->ether_hdr.d_addr.addr_bytes, hdr->ether_hdr.s_addr.addr_bytes, 6); - memcpy(hdr->ether_hdr.s_addr.addr_bytes, s_addr, 6); + build_arp_reply(hdr, s_addr); } static int handle_arp_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) diff --git a/VNFs/DPPD-PROX/handle_gen.c b/VNFs/DPPD-PROX/handle_gen.c index e5e43fca..f8c99ee5 100644 --- a/VNFs/DPPD-PROX/handle_gen.c +++ b/VNFs/DPPD-PROX/handle_gen.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "prox_shared.h" #include "random.h" @@ -45,22 +46,15 @@ #include "local_mbuf.h" #include "arp.h" #include "tx_pkt.h" -#include +#include "handle_master.h" struct pkt_template { - uint64_t dst_mac; - uint32_t ip_src; - uint32_t ip_dst_pos; uint16_t len; uint16_t l2_len; uint16_t l3_len; uint8_t buf[ETHER_MAX_LEN]; }; -#define FLAG_DST_MAC_KNOWN 1 -#define FLAG_L3_GEN 2 -#define FLAG_RANDOM_IPS 4 - #define MAX_TEMPLATE_INDEX 65536 #define TEMPLATE_INDEX_MASK (MAX_TEMPLATE_INDEX - 1) #define MBUF_ARP MAX_TEMPLATE_INDEX @@ -125,12 +119,7 @@ struct task_gen { uint64_t accur[64]; uint64_t pkt_tsc_offset[64]; struct pkt_template *pkt_template_orig; /* packet templates (from inline or from pcap) */ - struct ether_addr gw_mac; struct ether_addr src_mac; - struct rte_hash *mac_hash; - uint64_t *dst_mac; - uint32_t gw_ip; - uint32_t src_ip; uint8_t flags; uint8_t cksum_offload; } __rte_cache_aligned; @@ -207,22 +196,6 @@ static void task_gen_reset_token_time(struct task_gen *task) token_time_reset(&task->token_time, rte_rdtsc(), 0); } -static void start(struct task_base *tbase) -{ - struct task_gen *task = (struct task_gen *)tbase; - task->pkt_queue_index = 0; - - task_gen_reset_token_time(task); -} - -static void start_pcap(struct task_base *tbase) -{ - struct task_gen_pcap *task = (struct task_gen_pcap *)tbase; - /* When we start, the first packet is sent immediately. */ - task->last_tsc = rte_rdtsc() - task->proto_tsc[0]; - task->pkt_idx = 0; -} - static void task_gen_take_count(struct task_gen *task, uint32_t send_bulk) { if (task->pkt_count == (uint32_t)-1) @@ -337,13 +310,7 @@ static uint32_t task_gen_calc_send_bulk(const struct task_gen *task, uint32_t *t */ for (uint16_t j = 0; j < max_bulk; ++j) { struct pkt_template *pktpl = &task->pkt_template[pkt_idx_tmp]; - if (unlikely((task->flags & (FLAG_L3_GEN | FLAG_DST_MAC_KNOWN)) == FLAG_L3_GEN)) { - // Generator is supposed to get MAC address - MAC is still unknown for this template - // generate ARP Request to gateway instead of the intended packet - pkt_size = 60; - } else { - pkt_size = pktpl->len; - } + pkt_size = pktpl->len; uint32_t pkt_len = pkt_len_to_wire_size(pkt_size); if (pkt_len + would_send_bytes > task->token_time.bytes_now) break; @@ -360,106 +327,6 @@ static uint32_t task_gen_calc_send_bulk(const struct task_gen *task, uint32_t *t return send_bulk; } -static inline void create_arp(struct rte_mbuf *mbuf, uint8_t *pkt_hdr, uint64_t *src_mac, uint32_t ip_dst, uint32_t ip_src) -{ - uint64_t mac_bcast = 0xFFFFFFFFFFFF; - rte_pktmbuf_pkt_len(mbuf) = 42; - rte_pktmbuf_data_len(mbuf) = 42; - init_mbuf_seg(mbuf); - struct ether_hdr_arp *hdr_arp = (struct ether_hdr_arp *)pkt_hdr; - - memcpy(&hdr_arp->ether_hdr.d_addr.addr_bytes, &mac_bcast, 6); - memcpy(&hdr_arp->ether_hdr.s_addr.addr_bytes, src_mac, 6); - hdr_arp->ether_hdr.ether_type = ETYPE_ARP; - hdr_arp->arp.htype = 0x100, - hdr_arp->arp.ptype = 0x0008; - hdr_arp->arp.hlen = 6; - hdr_arp->arp.plen = 4; - hdr_arp->arp.oper = 0x100; - hdr_arp->arp.data.spa = ip_src; - hdr_arp->arp.data.tpa = ip_dst; - memset(&hdr_arp->arp.data.tha, 0, sizeof(struct ether_addr)); - memcpy(&hdr_arp->arp.data.sha, src_mac, sizeof(struct ether_addr)); -} - -static int task_gen_write_dst_mac(struct task_gen *task, struct rte_mbuf **mbufs, uint8_t **pkt_hdr, uint32_t count) -{ - uint32_t ip_dst_pos, ip_src_pos, ip_dst, ip_src; - uint16_t i; - int ret; - - if (task->flags & FLAG_L3_GEN) { - if (task->gw_ip) { - if (unlikely((task->flags & FLAG_DST_MAC_KNOWN) == 0)) { - for (i = 0; i < count; ++i) { - struct pkt_template *pktpl = &task->pkt_template[mbufs[i]->udata64 & TEMPLATE_INDEX_MASK]; - create_arp(mbufs[i], pkt_hdr[i], (uint64_t *)&pktpl->buf[6], task->gw_ip, pktpl->ip_src); - mbufs[i]->udata64 |= MBUF_ARP; - } - } else { - for (i = 0; i < count; ++i) { - struct ether_hdr *hdr = (struct ether_hdr *)pkt_hdr[i]; - memcpy(&hdr->d_addr.addr_bytes, &task->gw_mac, 6); - } - } - } else if (unlikely((task->flags & FLAG_RANDOM_IPS) != 0) || (task->n_pkts >= 4)){ - // Find mac in lookup table. Send ARP if not found - int32_t positions[MAX_PKT_BURST], idx; - void *keys[MAX_PKT_BURST]; - uint32_t key[MAX_PKT_BURST]; - for (i = 0; i < count; ++i) { - uint8_t *hdr = (uint8_t *)pkt_hdr[i]; - struct pkt_template *pktpl = &task->pkt_template[mbufs[i]->udata64 & TEMPLATE_INDEX_MASK]; - ip_dst_pos = pktpl->ip_dst_pos; - ip_dst = *(uint32_t *)(hdr + ip_dst_pos); - key[i] = ip_dst; - keys[i] = &key[i]; - } - ret = rte_hash_lookup_bulk(task->mac_hash, (const void **)&keys, count, positions); - if (unlikely(ret < 0)) { - plogx_err("lookup_bulk failed in mac_hash\n"); - tx_pkt_drop_all((struct task_base *)task, mbufs, count, NULL); - return -1; - } - for (i = 0; i < count; ++i) { - idx = positions[i]; - if (unlikely(idx < 0)) { - // mac not found for this IP - struct pkt_template *pktpl = &task->pkt_template[mbufs[i]->udata64 & TEMPLATE_INDEX_MASK]; - uint8_t *hdr = (uint8_t *)pkt_hdr[i]; - ip_src_pos = pktpl->ip_dst_pos - 4; - ip_src = *(uint32_t *)(hdr + ip_src_pos); - create_arp(mbufs[i], pkt_hdr[i], (uint64_t *)&hdr[6], key[i], ip_src); - mbufs[i]->udata64 |= MBUF_ARP; - } else { - // mac found for this IP - struct ether_hdr_arp *hdr_arp = (struct ether_hdr_arp *)pkt_hdr[i]; - memcpy(&hdr_arp->ether_hdr.d_addr.addr_bytes, &task->dst_mac[idx], 6); - } - } - } else { - for (i = 0; i < count; ++i) { - uint8_t *hdr = (uint8_t *)pkt_hdr[i]; - struct pkt_template *pktpl = &task->pkt_template[mbufs[i]->udata64 & TEMPLATE_INDEX_MASK]; - - // Check if packet template already has the mac - if (unlikely(pktpl->dst_mac == 0)) { - // no random_ip, can take from from packet template but no mac (yet) - uint32_t ip_dst_pos = pktpl->ip_dst_pos; - ip_dst = *(uint32_t *)(hdr + ip_dst_pos); - create_arp(mbufs[i], pkt_hdr[i], (uint64_t *)&pktpl->buf[6], ip_dst, pktpl->ip_src); - mbufs[i]->udata64 |= MBUF_ARP; - } else { - // no random ip, mac known - struct ether_hdr_arp *hdr_arp = (struct ether_hdr_arp *)pkt_hdr[i]; - memcpy(&hdr_arp->ether_hdr.d_addr.addr_bytes, &pktpl->dst_mac, 6); - } - } - } - } - return 0; -} - static void task_gen_apply_random_fields(struct task_gen *task, uint8_t *hdr) { uint32_t ret, ret_tmp; @@ -690,92 +557,79 @@ static void task_gen_update_config(struct task_gen *task) task_gen_reset_token_time(task); } -static inline void handle_arp_pkts(struct task_gen *task, struct rte_mbuf **mbufs, uint16_t n_pkts) +static inline void build_value(struct task_gen *task, uint32_t mask, int bit_pos, uint32_t val, uint32_t fixed_bits) { - int j; - int ret; - struct ether_hdr_arp *hdr; - uint8_t out[MAX_PKT_BURST]; - static struct my_arp_t arp_reply = { - .htype = 0x100, - .ptype = 8, - .hlen = 6, - .plen = 4, - .oper = 0x200 - }; - static struct my_arp_t arp_request = { - .htype = 0x100, - .ptype = 8, - .hlen = 6, - .plen = 4, - .oper = 0x100 - }; - - for (j = 0; j < n_pkts; ++j) { - PREFETCH0(mbufs[j]); - } - for (j = 0; j < n_pkts; ++j) { - PREFETCH0(rte_pktmbuf_mtod(mbufs[j], void *)); + struct task_base *tbase = (struct task_base *)task; + if (bit_pos < 32) { + build_value(task, mask >> 1, bit_pos + 1, val, fixed_bits); + if (mask & 1) { + build_value(task, mask >> 1, bit_pos + 1, val | (1 << bit_pos), fixed_bits); + } + } else { + register_ip_to_ctrl_plane(tbase->l3.tmaster, rte_cpu_to_be_32(val | fixed_bits), tbase->l3.reachable_port_id, tbase->l3.core_id, tbase->l3.task_id); } - for (j = 0; j < n_pkts; ++j) { - hdr = rte_pktmbuf_mtod(mbufs[j], struct ether_hdr_arp *); - if (hdr->ether_hdr.ether_type == ETYPE_ARP) { - if (memcmp(&hdr->arp, &arp_reply, 8) == 0) { - uint32_t ip = hdr->arp.data.spa; - // plog_info("Received ARP Reply for IP %x\n",ip); - if (ip == task->gw_ip) { - memcpy(&task->gw_mac, &hdr->arp.data.sha, 6);; - task->flags |= FLAG_DST_MAC_KNOWN; - out[j] = OUT_HANDLED; - continue; - } else if ((task->n_pkts >= 4) || (task->flags & FLAG_RANDOM_IPS)) { - // Ideally, we should add the key when making the arp request, - // We should only store the mac address key was created. - // Here we are storing MAC we did not asked for... - ret = rte_hash_add_key(task->mac_hash, (const void *)&ip); - if (ret < 0) { - plogx_info("Unable add ip %d.%d.%d.%d in mac_hash\n", IP4(ip)); - out[j] = OUT_DISCARD; - } else { - task->dst_mac[ret] = *(uint64_t *)&(hdr->arp.data.sha); - out[j] = OUT_HANDLED; - } - continue; - } - // Need to find template back... - // Only try this if there are few templates - for (unsigned int idx = 0; idx < task->n_pkts; idx++) { - struct pkt_template *pktpl = &task->pkt_template[idx]; - uint32_t ip_dst_pos = pktpl->ip_dst_pos; - uint32_t *ip_dst = (uint32_t *)(((uint8_t *)pktpl->buf) + ip_dst_pos); - if (*ip_dst == ip) { - pktpl->dst_mac = *(uint64_t *)&(hdr->arp.data.sha); - } - out[j] = OUT_HANDLED; - } - } else if (memcmp(&hdr->arp, &arp_request, 8) == 0) { - struct ether_addr s_addr; - if (!task->src_ip) { - create_mac(hdr, &s_addr); - prepare_arp_reply(hdr, &s_addr); - memcpy(hdr->ether_hdr.d_addr.addr_bytes, hdr->ether_hdr.s_addr.addr_bytes, 6); - memcpy(hdr->ether_hdr.s_addr.addr_bytes, &s_addr, 6); - out[j] = 0; - } else if (hdr->arp.data.tpa == task->src_ip) { - prepare_arp_reply(hdr, &task->src_mac); - memcpy(hdr->ether_hdr.d_addr.addr_bytes, hdr->ether_hdr.s_addr.addr_bytes, 6); - memcpy(hdr->ether_hdr.s_addr.addr_bytes, &task->src_mac, 6); - out[j] = 0; +} +static inline void register_all_ip_to_ctrl_plane(struct task_gen *task) +{ + struct task_base *tbase = (struct task_base *)task; + int i, len, fixed; + unsigned int offset; + uint32_t mask; + + for (uint32_t i = 0; i < task->n_pkts; ++i) { + struct pkt_template *pktpl = &task->pkt_template[i]; + unsigned int ip_src_pos = 0; + int maybe_ipv4 = 0; + unsigned int l2_len = sizeof(struct ether_hdr); + + uint8_t *pkt = pktpl->buf; + struct ether_hdr *eth_hdr = (struct ether_hdr*)pkt; + uint16_t ether_type = eth_hdr->ether_type; + struct vlan_hdr *vlan_hdr; + + // Unstack VLAN tags + while (((ether_type == ETYPE_8021ad) || (ether_type == ETYPE_VLAN)) && (l2_len + sizeof(struct vlan_hdr) < pktpl->len)) { + vlan_hdr = (struct vlan_hdr *)(pkt + l2_len); + l2_len +=4; + ether_type = vlan_hdr->eth_proto; + } + if ((ether_type == ETYPE_MPLSU) || (ether_type == ETYPE_MPLSM)) { + l2_len +=4; + maybe_ipv4 = 1; + } + if ((ether_type != ETYPE_IPv4) && !maybe_ipv4) + continue; + + struct ipv4_hdr *ip = (struct ipv4_hdr *)(pkt + l2_len); + PROX_PANIC(ip->version_ihl >> 4 != 4, "IPv4 ether_type but IP version = %d != 4", ip->version_ihl >> 4); + + // Even if IPv4 header contains options, options are after ip src and dst + ip_src_pos = l2_len + sizeof(struct ipv4_hdr) - 2 * sizeof(uint32_t); + uint32_t *ip_src = ((uint32_t *)(pktpl->buf + ip_src_pos)); + plog_info("\tip_src_pos = %d, ip_src = %x\n", ip_src_pos, *ip_src); + register_ip_to_ctrl_plane(tbase->l3.tmaster, *ip_src, tbase->l3.reachable_port_id, tbase->l3.core_id, tbase->l3.task_id); + + for (int j = 0; j < task->n_rands; j++) { + offset = task->rand[j].rand_offset; + len = task->rand[j].rand_len; + mask = task->rand[j].rand_mask; + fixed = task->rand[j].fixed_bits; + plog_info("offset = %d, len = %d, mask = %x, fixed = %x\n", offset, len, mask, fixed); + if ((offset < ip_src_pos + 4) && (offset + len >= ip_src_pos)) { + if (offset >= ip_src_pos) { + int32_t ip_src_mask = (1 << (4 + ip_src_pos - offset) * 8) - 1; + mask = mask & ip_src_mask; + fixed = (fixed & ip_src_mask) | (rte_be_to_cpu_32(*ip_src) & ~ip_src_mask); + build_value(task, mask, 0, 0, fixed); } else { - out[j] = OUT_DISCARD; - plogx_dbg("Received ARP on unexpected IP %x, expecting %x\n", rte_be_to_cpu_32(hdr->arp.data.tpa), rte_be_to_cpu_32(task->src_ip)); + int32_t bits = ((ip_src_pos + 4 - offset - len) * 8); + mask = mask << bits; + fixed = (fixed << bits) | (rte_be_to_cpu_32(*ip_src) & ((1 << bits) - 1)); + build_value(task, mask, 0, 0, fixed); } } - } else { - out[j] = OUT_DISCARD; } } - ret = task->base.tx_pkt(&task->base, mbufs, n_pkts, out); } static int handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) @@ -786,10 +640,6 @@ static int handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin int i, j; - if (unlikely((task->flags & FLAG_L3_GEN) && (n_pkts != 0))) { - handle_arp_pkts(task, mbufs, n_pkts); - } - task_gen_update_config(task); if (task->pkt_count == 0) { @@ -802,7 +652,7 @@ static int handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin token_time_update(&task->token_time, rte_rdtsc()); uint32_t would_send_bytes; - const uint32_t send_bulk = task_gen_calc_send_bulk(task, &would_send_bytes); + uint32_t send_bulk = task_gen_calc_send_bulk(task, &would_send_bytes); if (send_bulk == 0) return 0; @@ -817,8 +667,6 @@ static int handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin task_gen_load_and_prefetch(new_pkts, pkt_hdr, send_bulk); task_gen_build_packets(task, new_pkts, pkt_hdr, send_bulk); task_gen_apply_all_random_fields(task, pkt_hdr, send_bulk); - if (task_gen_write_dst_mac(task, new_pkts, pkt_hdr, send_bulk) < 0) - return 0; task_gen_apply_all_accur_pos(task, new_pkts, pkt_hdr, send_bulk); task_gen_apply_all_sig(task, new_pkts, pkt_hdr, send_bulk); task_gen_apply_all_unique_id(task, new_pkts, pkt_hdr, send_bulk); @@ -1135,13 +983,6 @@ int task_gen_set_pkt_size(struct task_base *tbase, uint32_t pkt_size) return rc; } -void task_gen_set_gateway_ip(struct task_base *tbase, uint32_t ip) -{ - struct task_gen *task = (struct task_gen *)tbase; - task->gw_ip = ip; - task->flags &= ~FLAG_DST_MAC_KNOWN; -} - void task_gen_set_rate(struct task_base *tbase, uint64_t bps) { struct task_gen *task = (struct task_gen *)tbase; @@ -1159,7 +1000,6 @@ void task_gen_reset_randoms(struct task_base *tbase) task->rand[i].rand_offset = 0; } task->n_rands = 0; - task->flags &= ~FLAG_RANDOM_IPS; } int task_gen_set_value(struct task_base *tbase, uint32_t value, uint32_t offset, uint32_t len) @@ -1276,16 +1116,37 @@ int task_gen_add_rand(struct task_base *tbase, const char *rand_str, uint32_t of task->rand[task->n_rands].rand_mask = mask; task->rand[task->n_rands].fixed_bits = fixed; - struct pkt_template *pktpl = &task->pkt_template[0]; - if (!((offset >= pktpl->ip_dst_pos + 4) || (offset + len < pktpl->ip_dst_pos))) { - plog_info("\tUsing randoms IP destinations\n"); - task->flags |= FLAG_RANDOM_IPS; - } - task->n_rands++; return 0; } +static void start(struct task_base *tbase) +{ + struct task_gen *task = (struct task_gen *)tbase; + task->pkt_queue_index = 0; + + task_gen_reset_token_time(task); + if (tbase->l3.tmaster) { + register_all_ip_to_ctrl_plane(task); + } + /* TODO + Handle the case when two tasks transmit to the same port + and one of them is stopped. In that case ARP (requests or replies) + might not be sent. Master will have to keep a list of rings. + stop will have to de-register IP from ctrl plane. + un-registration will remove the ring. when having more than + one active rings, master can always use the first one + */ +} + +static void start_pcap(struct task_base *tbase) +{ + struct task_gen_pcap *task = (struct task_gen_pcap *)tbase; + /* When we start, the first packet is sent immediately. */ + task->last_tsc = rte_rdtsc() - task->proto_tsc[0]; + task->pkt_idx = 0; +} + static void init_task_gen_early(struct task_args *targ) { uint8_t *generator_count = prox_sh_find_system("generator_count"); @@ -1353,70 +1214,6 @@ static void init_task_gen(struct task_base *tbase, struct task_args *targ) } } memcpy(&task->src_mac, &prox_port_cfg[task->base.tx_params_hw.tx_port_queue->port].eth_addr, sizeof(struct ether_addr)); - if (!strcmp(targ->task_init->sub_mode_str, "l3")) { - // In L3 GEN, we need to receive ARP replies - task->flags = FLAG_L3_GEN; - task->gw_ip = rte_cpu_to_be_32(targ->gateway_ipv4); - uint32_t n_entries; - - if (targ->number_gen_ip == 0) - n_entries = 1048576; - else - n_entries = targ->number_gen_ip; - - static char hash_name[30]; - sprintf(hash_name, "A%03d_mac_table", targ->lconf->id); - - struct rte_hash_parameters hash_params = { - .name = hash_name, - .entries = n_entries, - .key_len = sizeof(uint32_t), - .hash_func = rte_hash_crc, - .hash_func_init_val = 0, - }; - task->mac_hash = rte_hash_create(&hash_params); - PROX_PANIC(task->mac_hash == NULL, "Failed to set up mac hash table for %d IP\n", n_entries); - - const uint32_t socket = rte_lcore_to_socket_id(targ->lconf->id); - task->dst_mac = (uint64_t *)prox_zmalloc(n_entries * sizeof(uint64_t), socket); - PROX_PANIC(task->dst_mac == NULL, "Failed to allocate mac table for %d IP\n", n_entries); - - for (uint32_t i = 0; i < task->n_pkts; ++i) { - // For all destination IP, ARP request will need to be sent - // Store position of Destination IP in template - int ip_dst_pos = 0; - int maybe_ipv4 = 0; - int l2_len = sizeof(struct ether_hdr); - struct vlan_hdr *vlan_hdr; - uint8_t *pkt = task->pkt_template[i].buf; - struct ether_hdr *eth_hdr = (struct ether_hdr*)pkt; - struct ipv4_hdr *ip; - uint16_t ether_type = eth_hdr->ether_type; - - // Unstack VLAN tags - while (((ether_type == ETYPE_8021ad) || (ether_type == ETYPE_VLAN)) && (l2_len + sizeof(struct vlan_hdr) < task->pkt_template[i].len)) { - vlan_hdr = (struct vlan_hdr *)(pkt + l2_len); - l2_len +=4; - ether_type = vlan_hdr->eth_proto; - } - if ((ether_type == ETYPE_MPLSU) || (ether_type == ETYPE_MPLSM)) { - l2_len +=4; - maybe_ipv4 = 1; - } - if ((ether_type == ETYPE_IPv4) || maybe_ipv4) { - struct ipv4_hdr *ip = (struct ipv4_hdr *)(pkt + l2_len); - PROX_PANIC(ip->version_ihl >> 4 != 4, "IPv4 ether_type but IP version = %d != 4", ip->version_ihl >> 4); - // Even if IPv4 header contains options, options are after ip src and dst - ip_dst_pos = l2_len + sizeof(struct ipv4_hdr) - sizeof(uint32_t); - uint32_t *p = ((uint32_t *)(task->pkt_template[i].buf + ip_dst_pos - sizeof(uint32_t))); - task->pkt_template[i].ip_dst_pos = ip_dst_pos; - task->pkt_template[i].ip_src = *p; - uint32_t *p1 = ((uint32_t *)(task->pkt_template[i].buf + ip_dst_pos)); - plog_info("\tip_dst_pos = %d, ip_dst = %x\n", ip_dst_pos, *p1); - } - } - task->src_ip = rte_cpu_to_be_32(targ->local_ipv4); - } for (uint32_t i = 0; i < targ->n_rand_str; ++i) { PROX_PANIC(task_gen_add_rand(tbase, targ->rand_str[i], targ->rand_offset[i], UINT32_MAX), "Failed to add random\n"); @@ -1452,9 +1249,9 @@ static struct task_init task_init_gen_l3 = { #ifdef SOFT_CRC // For SOFT_CRC, no offload is needed. If both NOOFFLOADS and NOMULTSEGS flags are set the // vector mode is used by DPDK, resulting (theoretically) in higher performance. - .flag_features = TASK_FEATURE_ZERO_RX | TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS | TASK_FEATURE_TXQ_FLAGS_NOMULTSEGS|TASK_FEATURE_ZERO_RX, + .flag_features = TASK_FEATURE_NEVER_DISCARDS | TASK_FEATURE_NO_RX | TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS | TASK_FEATURE_TXQ_FLAGS_NOMULTSEGS, #else - .flag_features = TASK_FEATURE_ZERO_RX, + .flag_features = TASK_FEATURE_NEVER_DISCARDS | TASK_FEATURE_NO_RX, #endif .size = sizeof(struct task_gen) }; diff --git a/VNFs/DPPD-PROX/handle_gen.h b/VNFs/DPPD-PROX/handle_gen.h index 6f00ca12..5083fea9 100644 --- a/VNFs/DPPD-PROX/handle_gen.h +++ b/VNFs/DPPD-PROX/handle_gen.h @@ -39,7 +39,6 @@ struct task_base; void task_gen_set_pkt_count(struct task_base *tbase, uint32_t count); int task_gen_set_pkt_size(struct task_base *tbase, uint32_t pkt_size); void task_gen_set_rate(struct task_base *tbase, uint64_t bps); -void task_gen_set_gateway_ip(struct task_base *tbase, uint32_t ip); void task_gen_reset_randoms(struct task_base *tbase); void task_gen_reset_values(struct task_base *tbase); int task_gen_set_value(struct task_base *tbase, uint32_t value, uint32_t offset, uint32_t len); diff --git a/VNFs/DPPD-PROX/handle_impair.c b/VNFs/DPPD-PROX/handle_impair.c index 3f2ee0eb..78c9e400 100644 --- a/VNFs/DPPD-PROX/handle_impair.c +++ b/VNFs/DPPD-PROX/handle_impair.c @@ -25,6 +25,7 @@ #include "random.h" #include "handle_impair.h" #include "prefetch.h" +#include "prox_port_cfg.h" #if RTE_VERSION < RTE_VERSION_NUM(1,8,0,0) #define RTE_CACHE_LINE_SIZE CACHE_LINE_SIZE @@ -60,9 +61,13 @@ struct task_impair { uint64_t last_idx; struct queue *buffer; uint32_t socket_id; - int need_update; + uint32_t flags; + uint8_t src_mac[6]; }; +#define IMPAIR_NEED_UPDATE 1 +#define IMPAIR_SET_MAC 2 + static int handle_bulk_impair(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts); static int handle_bulk_impair_random(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts); static int handle_bulk_random_drop(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts); @@ -76,7 +81,7 @@ void task_impair_set_proba(struct task_base *tbase, float proba) void task_impair_set_delay_us(struct task_base *tbase, uint32_t delay_us, uint32_t random_delay_us) { struct task_impair *task = (struct task_impair *)tbase; - task->need_update = 1; + task->flags |= IMPAIR_NEED_UPDATE; task->random_delay_us = random_delay_us; task->delay_us = delay_us; } @@ -86,9 +91,9 @@ static void task_impair_update(struct task_base *tbase) struct task_impair *task = (struct task_impair *)tbase; uint32_t queue_len = 0; size_t mem_size; - if (!task->need_update) + if ((task->flags & IMPAIR_NEED_UPDATE) == 0) return; - task->need_update = 0; + task->flags &= ~IMPAIR_NEED_UPDATE; uint64_t now = rte_rdtsc(); uint8_t out[MAX_PKT_BURST] = {0}; uint64_t now_idx = (now >> DELAY_ACCURACY) & DELAY_MAX_MASK; @@ -187,8 +192,23 @@ static int handle_bulk_random_drop(struct task_base *tbase, struct rte_mbuf **mb { struct task_impair *task = (struct task_impair *)tbase; uint8_t out[MAX_PKT_BURST]; + struct ether_hdr * hdr[MAX_PKT_BURST]; + for (uint16_t i = 0; i < n_pkts; ++i) { + PREFETCH0(mbufs[i]); + } for (uint16_t i = 0; i < n_pkts; ++i) { - out[i] = rand_r(&task->seed) <= task->tresh? 0 : OUT_DISCARD; + hdr[i] = rte_pktmbuf_mtod(mbufs[i], struct ether_hdr *); + PREFETCH0(hdr[i]); + } + if (task->flags & IMPAIR_SET_MAC) { + for (uint16_t i = 0; i < n_pkts; ++i) { + ether_addr_copy((struct ether_addr *)&task->src_mac[0], &hdr[i]->s_addr); + out[i] = rand_r(&task->seed) <= task->tresh? 0 : OUT_DISCARD; + } + } else { + for (uint16_t i = 0; i < n_pkts; ++i) { + out[i] = rand_r(&task->seed) <= task->tresh? 0 : OUT_DISCARD; + } } return task->base.tx_pkt(&task->base, mbufs, n_pkts, out); task_impair_update(tbase); @@ -202,11 +222,21 @@ static int handle_bulk_impair(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t enqueue_failed; uint16_t i; int ret = 0; + struct ether_hdr * hdr[MAX_PKT_BURST]; + for (uint16_t i = 0; i < n_pkts; ++i) { + PREFETCH0(mbufs[i]); + } + for (uint16_t i = 0; i < n_pkts; ++i) { + hdr[i] = rte_pktmbuf_mtod(mbufs[i], struct ether_hdr *); + PREFETCH0(hdr[i]); + } int nb_empty_slots = (task->queue_tail - task->queue_head + task->queue_mask) & task->queue_mask; if (likely(nb_empty_slots >= n_pkts)) { /* We know n_pkts fits, no need to check for every packet */ for (i = 0; i < n_pkts; ++i) { + if (task->flags & IMPAIR_SET_MAC) + ether_addr_copy((struct ether_addr *)&task->src_mac[0], &hdr[i]->s_addr); task->queue[task->queue_head].tsc = now + task->delay_time; task->queue[task->queue_head].mbuf = mbufs[i]; task->queue_head = (task->queue_head + 1) & task->queue_mask; @@ -214,6 +244,8 @@ static int handle_bulk_impair(struct task_base *tbase, struct rte_mbuf **mbufs, } else { for (i = 0; i < n_pkts; ++i) { if (((task->queue_head + 1) & task->queue_mask) != task->queue_tail) { + if (task->flags & IMPAIR_SET_MAC) + ether_addr_copy((struct ether_addr *)&task->src_mac[0], &hdr[i]->s_addr); task->queue[task->queue_head].tsc = now + task->delay_time; task->queue[task->queue_head].mbuf = mbufs[i]; task->queue_head = (task->queue_head + 1) & task->queue_mask; @@ -302,6 +334,14 @@ static int handle_bulk_impair_random(struct task_base *tbase, struct rte_mbuf ** int ret = 0; uint64_t packet_time, idx; uint64_t now_idx = (now >> DELAY_ACCURACY) & DELAY_MAX_MASK; + struct ether_hdr * hdr[MAX_PKT_BURST]; + for (uint16_t i = 0; i < n_pkts; ++i) { + PREFETCH0(mbufs[i]); + } + for (uint16_t i = 0; i < n_pkts; ++i) { + hdr[i] = rte_pktmbuf_mtod(mbufs[i], struct ether_hdr *); + PREFETCH0(hdr[i]); + } for (i = 0; i < n_pkts; ++i) { packet_time = now + random_delay(&task->state, task->delay_time, task->delay_time_mask); @@ -309,6 +349,8 @@ static int handle_bulk_impair_random(struct task_base *tbase, struct rte_mbuf ** while (idx != ((now_idx - 1) & DELAY_MAX_MASK)) { struct queue *queue = &task->buffer[idx]; if (((queue->queue_head + 1) & task->queue_mask) != queue->queue_tail) { + if (task->flags & IMPAIR_SET_MAC) + ether_addr_copy((struct ether_addr *)&task->src_mac[0], &hdr[i]->s_addr); queue->queue_elem[queue->queue_head].mbuf = mbufs[i]; queue->queue_head = (queue->queue_head + 1) & task->queue_mask; break; @@ -405,6 +447,12 @@ static void init_task(struct task_base *tbase, struct task_args *targ) } } random_init_seed(&task->state); + if (targ->nb_txports) { + memcpy(&task->src_mac[0], &prox_port_cfg[tbase->tx_params_hw.tx_port_queue[0].port].eth_addr, sizeof(struct ether_addr)); + task->flags = IMPAIR_SET_MAC; + } else { + task->flags = 0; + } } static struct task_init tinit = { diff --git a/VNFs/DPPD-PROX/handle_irq.c b/VNFs/DPPD-PROX/handle_irq.c index 4abf84a1..86640c69 100644 --- a/VNFs/DPPD-PROX/handle_irq.c +++ b/VNFs/DPPD-PROX/handle_irq.c @@ -39,6 +39,7 @@ struct irq_bucket { struct task_irq { struct task_base base; uint64_t start_tsc; + uint64_t first_tsc; uint64_t tsc; uint64_t max_irq; uint8_t lcore_id; @@ -99,9 +100,12 @@ static void irq_stop(struct task_base *tbase) struct task_irq *task = (struct task_irq *)tbase; uint32_t i; uint32_t lcore_id = rte_lcore_id(); + uint64_t lat, max_lat = 0, tot_lat = 0; int bucket_id; + int n_lat = 0; plog_info("Stopping core %u\n", lcore_id); + sleep(2); // Make sure all cores are stopped before starting to write plog_info("Core ID; Interrupt (nanosec); Time (msec)\n"); for (int j = 0; j < 2; j++) { // Start dumping the oldest bucket first @@ -112,14 +116,19 @@ static void irq_stop(struct task_base *tbase) struct irq_bucket *bucket = &task->buffer[bucket_id]; for (i=0; i< bucket->index;i++) { if (bucket->info[i].lat != 0) { - plog_info("%d; %ld; %ld\n", - lcore_id, - bucket->info[i].lat * 1000000000 / rte_get_tsc_hz(), + lat = bucket->info[i].lat * 1000000000 / rte_get_tsc_hz(); + if (max_lat < lat) + max_lat = lat; + n_lat++; + tot_lat += lat; + plog_info("%d; %ld; %ld\n", lcore_id, lat, (bucket->info[i].tsc - task->start_tsc) * 1000 / rte_get_tsc_hz()); } } } - plog_info("Core %u stopped\n", lcore_id); + if (n_lat) + tot_lat = tot_lat / n_lat; + plog_info("Core %u stopped. max lat is %ld and average is %ld\n", lcore_id, max_lat, tot_lat); } static inline int handle_irq_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) @@ -133,7 +142,7 @@ static inline int handle_irq_bulk(struct task_base *tbase, struct rte_mbuf **mbu struct irq_bucket *bucket = &task->buffer[task->task_use_lt]; tsc1 = rte_rdtsc(); - if ((task->tsc != 0) && ((tsc1 - task->tsc) > task->max_irq) && (bucket->index < MAX_INDEX)) { + if ((tsc1 > task->first_tsc) && (task->tsc != 0) && ((tsc1 - task->tsc) > task->max_irq) && (bucket->index < MAX_INDEX)) { bucket->info[bucket->index].tsc = tsc1; bucket->info[bucket->index++].lat = tsc1 - task->tsc; } @@ -148,6 +157,7 @@ static void init_task_irq(struct task_base *tbase, // max_irq expressed in cycles task->max_irq = rte_get_tsc_hz() / MAX_INTERRUPT_LENGTH; task->start_tsc = rte_rdtsc(); + task->first_tsc = task->start_tsc + 2 * rte_get_tsc_hz(); task->lcore_id = targ->lconf->id; plog_info("\tusing irq mode with max irq set to %ld cycles\n", task->max_irq); } diff --git a/VNFs/DPPD-PROX/handle_master.c b/VNFs/DPPD-PROX/handle_master.c new file mode 100644 index 00000000..6bd4ea2c --- /dev/null +++ b/VNFs/DPPD-PROX/handle_master.c @@ -0,0 +1,348 @@ +/* +// Copyright (c) 2010-2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include +#include +#include "prox_cfg.h" + +#include "prox_globals.h" +#include "rx_pkt.h" +#include "arp.h" +#include "handle_master.h" +#include "log.h" +#include "mbuf_utils.h" +#include "etypes.h" +#include "defaults.h" +#include "prox_cfg.h" +#include "prox_malloc.h" +#include "quit.h" +#include "task_init.h" +#include "prox_port_cfg.h" +#include "main.h" +#include "lconf.h" +#include "input.h" +#include "tx_pkt.h" + +#define IP4(x) x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, x >> 24 + +const char *actions_string[] = {"UPDATE_FROM_CTRL", "SEND_ARP_REQUEST_FROM_CTRL", "SEND_ARP_REPLY_FROM_CTRL", "HANDLE_ARP_TO_CTRL", "REQ_MAC_TO_CTRL"}; + +static struct my_arp_t arp_reply = { + .htype = 0x100, + .ptype = 8, + .hlen = 6, + .plen = 4, + .oper = 0x200 +}; +static struct my_arp_t arp_request = { + .htype = 0x100, + .ptype = 8, + .hlen = 6, + .plen = 4, + .oper = 0x100 +}; + +struct ip_table { + struct ether_addr mac; + struct rte_ring *ring; +}; + +struct port_table { + struct ether_addr mac; + struct rte_ring *ring; + uint32_t ip; + uint8_t port; + uint8_t flags; +}; + +struct task_master { + struct task_base base; + struct rte_ring *ctrl_rx_ring; + struct rte_ring **ctrl_tx_rings; + struct ip_table *internal_ip_table; + struct ip_table *external_ip_table; + struct rte_hash *external_ip_hash; + struct rte_hash *internal_ip_hash; + struct port_table internal_port_table[PROX_MAX_PORTS]; +}; + +struct ip_port { + uint32_t ip; + uint8_t port; +} __attribute__((packed)); + +static inline uint8_t get_command(struct rte_mbuf *mbuf) +{ + return mbuf->udata64 & 0xFF; +} +static inline uint8_t get_task(struct rte_mbuf *mbuf) +{ + return (mbuf->udata64 >> 8) & 0xFF; +} +static inline uint8_t get_core(struct rte_mbuf *mbuf) +{ + return (mbuf->udata64 >> 16) & 0xFF; +} +static inline uint8_t get_port(struct rte_mbuf *mbuf) +{ + return mbuf->port; +} +static inline uint32_t get_ip(struct rte_mbuf *mbuf) +{ + return (mbuf->udata64 >> 32) & 0xFFFFFFFF; +} + +void register_ip_to_ctrl_plane(struct task_base *tbase, uint32_t ip, uint8_t port_id, uint8_t core_id, uint8_t task_id) +{ + struct task_master *task = (struct task_master *)tbase; + struct ip_port key; + plogx_dbg("\tregistering IP %x.%x.%x.%x with port %d core %d and task %d\n", IP4(ip), port_id, core_id, task_id); + + if (port_id >= PROX_MAX_PORTS) { + plog_err("Unable to register ip %x, port %d\n", ip, port_id); + return; + } + + /* TODO - stoe multiple rings if multiple cores able to handle IP + Remove them when such cores are stopped and de-register IP + */ + task->internal_port_table[port_id].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id]; + memcpy(&task->internal_port_table[port_id].mac, &prox_port_cfg[port_id].eth_addr, 6); + task->internal_port_table[port_id].ip = ip; + + if (ip == RANDOM_IP) { + task->internal_port_table[port_id].flags |= HANDLE_RANDOM_IP_FLAG; + return; + } + + key.ip = ip; + key.port = port_id; + int ret = rte_hash_add_key(task->internal_ip_hash, (const void *)&key); + if (unlikely(ret < 0)) { + plog_err("Unable to register ip %x\n", ip); + return; + } + memcpy(&task->internal_ip_table[ret].mac, &prox_port_cfg[port_id].eth_addr, 6); + task->internal_ip_table[ret].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id]; + +} + +static inline void handle_arp_reply(struct task_base *tbase, struct rte_mbuf *mbuf) +{ + struct task_master *task = (struct task_master *)tbase; + struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *); + int i, ret; + uint32_t key = hdr_arp->arp.data.spa; + plogx_dbg("\tMaster handling ARP reply for ip %x\n", key); + + ret = rte_hash_lookup(task->external_ip_hash, (const void *)&key); + if (unlikely(ret < 0)) { + // entry not found for this IP: we did not ask a request, delete the reply + tx_drop(mbuf); + } else { + // entry found for this IP + struct rte_ring *ring = task->external_ip_table[ret].ring; + memcpy(&hdr_arp->ether_hdr.d_addr.addr_bytes, &task->external_ip_table[ret].mac, 6); + tx_ring_ip(tbase, ring, UPDATE_FROM_CTRL, mbuf, key); + } +} + +static inline void handle_arp_request(struct task_base *tbase, struct rte_mbuf *mbuf) +{ + struct task_master *task = (struct task_master *)tbase; + struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *); + int i, ret; + uint8_t port = get_port(mbuf); + + struct ip_port key; + key.ip = hdr_arp->arp.data.tpa; + key.port = port; + if (task->internal_port_table[port].flags & HANDLE_RANDOM_IP_FLAG) { + struct ether_addr mac; + plogx_dbg("\tMaster handling ARP request for ip %x on port %d which supports random ip\n", key.ip, key.port); + struct rte_ring *ring = task->internal_port_table[port].ring; + create_mac(hdr_arp, &mac); + mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM); + build_arp_reply(hdr_arp, &mac); + tx_ring(tbase, ring, ARP_REPLY_FROM_CTRL, mbuf); + return; + } + + plogx_dbg("\tMaster handling ARP request for ip %x\n", key.ip); + + ret = rte_hash_lookup(task->internal_ip_hash, (const void *)&key); + if (unlikely(ret < 0)) { + // entry not found for this IP. + plogx_dbg("Master ignoring ARP REQUEST received on un-registered IP %d.%d.%d.%d on port %d\n", IP4(hdr_arp->arp.data.tpa), port); + tx_drop(mbuf); + } else { + struct rte_ring *ring = task->internal_ip_table[ret].ring; + mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM); + build_arp_reply(hdr_arp, &task->internal_ip_table[ret].mac); + tx_ring(tbase, ring, ARP_REPLY_FROM_CTRL, mbuf); + } +} + +static inline void handle_unknown_ip(struct task_base *tbase, struct rte_mbuf *mbuf) +{ + struct task_master *task = (struct task_master *)tbase; + struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *); + uint8_t port = get_port(mbuf); + uint32_t ip_dst = get_ip(mbuf); + int ret1, ret2; + + plogx_dbg("\tMaster handling unknown ip %x for port %d\n", ip_dst, port); + if (unlikely(port >= PROX_MAX_PORTS)) { + plogx_dbg("Port %d not found", port); + tx_drop(mbuf); + return; + } + uint32_t ip_src = task->internal_port_table[port].ip; + struct rte_ring *ring = task->ctrl_tx_rings[get_core(mbuf) * MAX_TASKS_PER_CORE + get_task(mbuf)]; + + if (ring == NULL) { + plogx_dbg("Port %d not registered", port); + tx_drop(mbuf); + return; + } + + ret2 = rte_hash_add_key(task->external_ip_hash, (const void *)&ip_dst); + if (unlikely(ret2 < 0)) { + // entry not found for this IP: delete the reply + plogx_dbg("Unable to add IP %x in external_ip_hash\n", rte_be_to_cpu_32(hdr_arp->arp.data.tpa)); + tx_drop(mbuf); + return; + } + task->external_ip_table[ret2].ring = ring; + memcpy(&task->external_ip_table[ret2].mac, &task->internal_port_table[port].mac, 6); + + mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM); + build_arp_request(mbuf, &task->internal_port_table[port].mac, ip_dst, ip_src); + tx_ring(tbase, ring, ARP_REQ_FROM_CTRL, mbuf); +} + +static inline void handle_message(struct task_base *tbase, struct rte_mbuf *mbuf, int ring_id) +{ + struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *); + int command = get_command(mbuf); + uint32_t ip; + plogx_dbg("\tMaster received %s (%x) from mbuf %p\n", actions_string[command], command, mbuf); + + switch(command) { + case ARP_TO_CTRL: + if (hdr_arp->ether_hdr.ether_type != ETYPE_ARP) { + tx_drop(mbuf); + plog_err("\tUnexpected message received: ARP_TO_CTRL with ether_type %x\n", hdr_arp->ether_hdr.ether_type); + return; + } else if (arp_is_gratuitous(hdr_arp)) { + plog_info("\tReceived gratuitous packet \n"); + tx_drop(mbuf); + return; + } else if (memcmp(&hdr_arp->arp, &arp_reply, 8) == 0) { + uint32_t ip = hdr_arp->arp.data.spa; + handle_arp_reply(tbase, mbuf); + } else if (memcmp(&hdr_arp->arp, &arp_request, 8) == 0) { + handle_arp_request(tbase, mbuf); + } else { + plog_info("\tReceived unexpected ARP operation %d\n", hdr_arp->arp.oper); + tx_drop(mbuf); + return; + } + break; + case REQ_MAC_TO_CTRL: + handle_unknown_ip(tbase, mbuf); + break; + default: + plogx_dbg("\tMaster received unexpected message\n"); + tx_drop(mbuf); + break; + } +} + +void init_ctrl_plane(struct task_base *tbase) +{ + prox_cfg.flags |= DSF_CTRL_PLANE_ENABLED; + struct task_master *task = (struct task_master *)tbase; + int socket = rte_lcore_to_socket_id(prox_cfg.master); + uint32_t n_entries = MAX_ARP_ENTRIES * 4; + static char hash_name[30]; + sprintf(hash_name, "A%03d_hash_arp_table", prox_cfg.master); + struct rte_hash_parameters hash_params = { + .name = hash_name, + .entries = n_entries, + .key_len = sizeof(uint32_t), + .hash_func = rte_hash_crc, + .hash_func_init_val = 0, + }; + task->external_ip_hash = rte_hash_create(&hash_params); + PROX_PANIC(task->external_ip_hash == NULL, "Failed to set up external ip hash\n"); + plog_info("\texternal ip hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len); + task->external_ip_table = (struct ip_table *)prox_zmalloc(n_entries * sizeof(struct ip_table), socket); + PROX_PANIC(task->external_ip_table == NULL, "Failed to allocate memory for %u entries in external ip table\n", n_entries); + plog_info("\texternal ip table, with %d entries of size %ld\n", n_entries, sizeof(struct ip_table)); + + hash_name[0]++; + hash_params.key_len = sizeof(struct ip_port); + task->internal_ip_hash = rte_hash_create(&hash_params); + PROX_PANIC(task->internal_ip_hash == NULL, "Failed to set up internal ip hash\n"); + plog_info("\tinternal ip hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len); + task->internal_ip_table = (struct ip_table *)prox_zmalloc(n_entries * sizeof(struct ip_table), socket); + PROX_PANIC(task->internal_ip_table == NULL, "Failed to allocate memory for %u entries in internal ip table\n", n_entries); + plog_info("\tinternal ip table, with %d entries of size %ld\n", n_entries, sizeof(struct ip_table)); +} + +static int handle_ctrl_plane_f(struct task_base *tbase, __attribute__((unused)) struct rte_mbuf **mbuf, uint16_t n_pkts) +{ + int ring_id, j, ret = 0; + struct rte_mbuf *mbufs[MAX_RING_BURST]; + struct task_master *task = (struct task_master *)tbase; + + /* Handle_master works differently than other handle functions + It is not handled by a DPDK dataplane core + It is no thread_generic based, hence do not receive packets the same way + */ + + ret = ring_deq(task->ctrl_rx_ring, mbufs); + for (j = 0; j < ret; j++) { + handle_message(tbase, mbufs[j], ring_id); + } + return ret; +} + +static void init_task_master(struct task_base *tbase, struct task_args *targs) +{ + if (prox_cfg.flags & DSF_CTRL_PLANE_ENABLED) { + struct task_master *task = (struct task_master *)tbase; + + task->ctrl_rx_ring = targs->lconf->ctrl_rings_p[0]; + task->ctrl_tx_rings = ctrl_rings; + init_ctrl_plane(tbase); + handle_ctrl_plane = handle_ctrl_plane_f; + } +} + +static struct task_init task_init_master = { + .mode_str = "master", + .init = init_task_master, + .handle = NULL, + .flag_features = TASK_FEATURE_NEVER_DISCARDS, + .size = sizeof(struct task_master) +}; + +__attribute__((constructor)) static void reg_task_gen(void) +{ + reg_task(&task_init_master); +} diff --git a/VNFs/DPPD-PROX/handle_master.h b/VNFs/DPPD-PROX/handle_master.h new file mode 100644 index 00000000..bc32182d --- /dev/null +++ b/VNFs/DPPD-PROX/handle_master.h @@ -0,0 +1,43 @@ +/* +// Copyright (c) 2010-2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "task_base.h" +#include "task_init.h" + +enum arp_actions { + UPDATE_FROM_CTRL, + ARP_REQ_FROM_CTRL, + ARP_REPLY_FROM_CTRL, + ARP_TO_CTRL, + REQ_MAC_TO_CTRL, + MAX_ACTIONS +}; + +#define HANDLE_RANDOM_IP_FLAG 1 +#define RANDOM_IP 0xffffffff + +const char *actions_string[MAX_ACTIONS]; + +void init_ctrl_plane(struct task_base *tbase); + +int (*handle_ctrl_plane)(struct task_base *tbase, struct rte_mbuf **mbuf, uint16_t n_pkts); + +static inline void tx_drop(struct rte_mbuf *mbuf) +{ + rte_pktmbuf_free(mbuf); +} + +void register_ip_to_ctrl_plane(struct task_base *task, uint32_t ip, uint8_t port_id, uint8_t core_id, uint8_t task_id); diff --git a/VNFs/DPPD-PROX/handle_swap.c b/VNFs/DPPD-PROX/handle_swap.c index 8e5a94ce..516d3f63 100644 --- a/VNFs/DPPD-PROX/handle_swap.c +++ b/VNFs/DPPD-PROX/handle_swap.c @@ -33,16 +33,8 @@ struct task_swap { struct task_base base; uint8_t src_dst_mac[12]; uint32_t runtime_flags; - uint32_t tmp_ip; - uint32_t ip; }; -static void task_update_config(struct task_swap *task) -{ - if (unlikely(task->ip != task->tmp_ip)) - task->ip = task->tmp_ip; -} - static void write_src_and_dst_mac(struct task_swap *task, struct rte_mbuf *mbuf) { struct ether_hdr *hdr; @@ -74,16 +66,12 @@ static void write_src_and_dst_mac(struct task_swap *task, struct rte_mbuf *mbuf) static inline int handle_arp_request(struct task_swap *task, struct ether_hdr_arp *hdr_arp, struct ether_addr *s_addr, uint32_t ip) { if ((hdr_arp->arp.data.tpa == ip) || (ip == 0)) { - prepare_arp_reply(hdr_arp, s_addr); - memcpy(hdr_arp->ether_hdr.d_addr.addr_bytes, hdr_arp->ether_hdr.s_addr.addr_bytes, 6); - memcpy(hdr_arp->ether_hdr.s_addr.addr_bytes, s_addr, 6); + build_arp_reply(hdr_arp, s_addr); return 0; } else if (task->runtime_flags & TASK_MULTIPLE_MAC) { struct ether_addr tmp_s_addr; create_mac(hdr_arp, &tmp_s_addr); - prepare_arp_reply(hdr_arp, &tmp_s_addr); - memcpy(hdr_arp->ether_hdr.d_addr.addr_bytes, hdr_arp->ether_hdr.s_addr.addr_bytes, 6); - memcpy(hdr_arp->ether_hdr.s_addr.addr_bytes, &tmp_s_addr, 6); + build_arp_reply(hdr_arp, &tmp_s_addr); return 0; } else { plogx_dbg("Received ARP on unexpected IP %x, expecting %x\n", rte_be_to_cpu_32(hdr_arp->arp.data.tpa), rte_be_to_cpu_32(ip)); @@ -127,20 +115,6 @@ static int handle_swap_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, ui for (uint16_t j = 0; j < n_pkts; ++j) { hdr = rte_pktmbuf_mtod(mbufs[j], struct ether_hdr *); switch (hdr->ether_type) { - case ETYPE_ARP: - hdr_arp = rte_pktmbuf_mtod(mbufs[j], struct ether_hdr_arp *); - if (arp_is_gratuitous(hdr_arp)) { - plog_info("Received gratuitous packet \n"); - out[j] = OUT_DISCARD; - } else if (hdr_arp->arp.oper == ARP_REQUEST) { - out[j] = handle_arp_request(task, hdr_arp, (struct ether_addr *)&task->src_dst_mac[6], task->ip); - } else if (hdr_arp->arp.oper == ARP_REPLY) { - out[j] = handle_arp_replies(task, hdr_arp); - } else { - plog_info("Received unexpected ARP operation %d\n", hdr_arp->arp.oper); - out[j] = OUT_DISCARD; - } - continue; case ETYPE_MPLSU: mpls = (struct mpls_hdr *)(hdr + 1); while (!(mpls->bytes & 0x00010000)) { @@ -220,7 +194,6 @@ static int handle_swap_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, ui } write_src_and_dst_mac(task, mbufs[j]); } - task_update_config(task); return task->base.tx_pkt(&task->base, mbufs, n_pkts, out); } @@ -261,8 +234,6 @@ static void init_task_swap(struct task_base *tbase, struct task_args *targ) } } task->runtime_flags = targ->flags; - task->ip = rte_cpu_to_be_32(targ->local_ipv4); - task->tmp_ip = task->ip; } static struct task_init task_init_swap = { diff --git a/VNFs/DPPD-PROX/handle_swap.h b/VNFs/DPPD-PROX/handle_swap.h index ef2fee04..b589051d 100644 --- a/VNFs/DPPD-PROX/handle_swap.h +++ b/VNFs/DPPD-PROX/handle_swap.h @@ -18,6 +18,5 @@ #define _HANDLE_SWAP_H_ struct task_base; -void task_swap_set_local_ip(struct task_base *tbase, uint32_t ip); #endif /* _HANDLE_SWAP_H_ */ diff --git a/VNFs/DPPD-PROX/input.c b/VNFs/DPPD-PROX/input.c index bb956bcd..5eb5e4ce 100644 --- a/VNFs/DPPD-PROX/input.c +++ b/VNFs/DPPD-PROX/input.c @@ -74,6 +74,33 @@ static int tsc_diff_to_tv(uint64_t beg, uint64_t end, struct timeval *tv) return 0; } +void input_proc(void) +{ + struct timeval tv; + fd_set in_fd; + int ret = 1; + + tv.tv_sec = 0; + tv.tv_usec = 0; + while (ret != 0) { + FD_ZERO(&in_fd); + + for (int i = 0; i < n_inputs; ++i) { + FD_SET(inputs[i]->fd, &in_fd); + } + + ret = select(max_input_fd + 1, &in_fd, NULL, NULL, &tv); + + if (ret > 0) { + for (int i = 0; i < n_inputs; ++i) { + if (FD_ISSET(inputs[i]->fd, &in_fd)) { + inputs[i]->proc_input(inputs[i]); + } + } + } + } +} + void input_proc_until(uint64_t deadline) { struct timeval tv; diff --git a/VNFs/DPPD-PROX/input.h b/VNFs/DPPD-PROX/input.h index 06f6b653..51d94986 100644 --- a/VNFs/DPPD-PROX/input.h +++ b/VNFs/DPPD-PROX/input.h @@ -31,5 +31,6 @@ int reg_input(struct input *in); void unreg_input(struct input *in); void input_proc_until(uint64_t deadline); +void input_proc(void); #endif /* _INPUT_H_ */ diff --git a/VNFs/DPPD-PROX/lconf.c b/VNFs/DPPD-PROX/lconf.c index 88d8f4f9..399c8a7d 100644 --- a/VNFs/DPPD-PROX/lconf.c +++ b/VNFs/DPPD-PROX/lconf.c @@ -223,10 +223,17 @@ int lconf_do_flags(struct lcore_cfg *lconf) if (lconf->msg.type == LCONF_MSG_DUMP || lconf->msg.type == LCONF_MSG_DUMP_TX) { t->aux->task_rt_dump.n_print_tx = lconf->msg.val; - if (t->aux->tx_pkt_orig) - t->tx_pkt = t->aux->tx_pkt_orig; - t->aux->tx_pkt_orig = t->tx_pkt; - t->tx_pkt = tx_pkt_dump; + if (t->tx_pkt == tx_pkt_l3) { + if (t->aux->tx_pkt_orig) + t->aux->tx_pkt_l2 = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = t->aux->tx_pkt_l2; + t->aux->tx_pkt_l2 = tx_pkt_dump; + } else { + if (t->aux->tx_pkt_orig) + t->tx_pkt = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = t->tx_pkt; + t->tx_pkt = tx_pkt_dump; + } } } break; @@ -238,16 +245,30 @@ int lconf_do_flags(struct lcore_cfg *lconf) if (task_base_get_original_rx_pkt_function(t) != rx_pkt_dummy) { task_base_add_rx_pkt_function(t, rx_pkt_trace); - if (t->aux->tx_pkt_orig) - t->tx_pkt = t->aux->tx_pkt_orig; - t->aux->tx_pkt_orig = t->tx_pkt; - t->tx_pkt = tx_pkt_trace; + if (t->tx_pkt == tx_pkt_l3) { + if (t->aux->tx_pkt_orig) + t->aux->tx_pkt_l2 = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = t->aux->tx_pkt_l2; + t->aux->tx_pkt_l2 = tx_pkt_trace; + } else { + if (t->aux->tx_pkt_orig) + t->tx_pkt = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = t->tx_pkt; + t->tx_pkt = tx_pkt_trace; + } } else { t->aux->task_rt_dump.n_print_tx = lconf->msg.val; - if (t->aux->tx_pkt_orig) - t->tx_pkt = t->aux->tx_pkt_orig; - t->aux->tx_pkt_orig = t->tx_pkt; - t->tx_pkt = tx_pkt_dump; + if (t->tx_pkt == tx_pkt_l3) { + if (t->aux->tx_pkt_orig) + t->aux->tx_pkt_l2 = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = t->aux->tx_pkt_l2; + t->aux->tx_pkt_l2 = tx_pkt_dump; + } else { + if (t->aux->tx_pkt_orig) + t->tx_pkt = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = t->tx_pkt; + t->tx_pkt = tx_pkt_dump; + } } } break; @@ -263,8 +284,13 @@ int lconf_do_flags(struct lcore_cfg *lconf) for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { t = lconf->tasks_all[task_id]; - t->aux->tx_pkt_orig = t->tx_pkt; - t->tx_pkt = tx_pkt_distr; + if (t->tx_pkt == tx_pkt_l3) { + t->aux->tx_pkt_orig = t->aux->tx_pkt_l2; + t->aux->tx_pkt_l2 = tx_pkt_distr; + } else { + t->aux->tx_pkt_orig = t->tx_pkt; + t->tx_pkt = tx_pkt_distr; + } memset(t->aux->tx_bucket, 0, sizeof(t->aux->tx_bucket)); lconf->flags |= LCONF_FLAG_TX_DISTR_ACTIVE; } @@ -280,8 +306,13 @@ int lconf_do_flags(struct lcore_cfg *lconf) for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { t = lconf->tasks_all[task_id]; if (t->aux->tx_pkt_orig) { - t->tx_pkt = t->aux->tx_pkt_orig; - t->aux->tx_pkt_orig = NULL; + if (t->tx_pkt == tx_pkt_l3) { + t->tx_pkt = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = NULL; + } else { + t->aux->tx_pkt_l2 = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = NULL; + } lconf->flags &= ~LCONF_FLAG_TX_DISTR_ACTIVE; } } @@ -318,8 +349,13 @@ int lconf_do_flags(struct lcore_cfg *lconf) for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { t = lconf->tasks_all[task_id]; - t->aux->tx_pkt_orig = t->tx_pkt; - t->tx_pkt = tx_pkt_bw; + if (t->tx_pkt == tx_pkt_l3) { + t->aux->tx_pkt_orig = t->aux->tx_pkt_l2; + t->aux->tx_pkt_l2 = tx_pkt_bw; + } else { + t->aux->tx_pkt_orig = t->tx_pkt; + t->tx_pkt = tx_pkt_bw; + } lconf->flags |= LCONF_FLAG_TX_BW_ACTIVE; } break; @@ -327,8 +363,13 @@ int lconf_do_flags(struct lcore_cfg *lconf) for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { t = lconf->tasks_all[task_id]; if (t->aux->tx_pkt_orig) { - t->tx_pkt = t->aux->tx_pkt_orig; - t->aux->tx_pkt_orig = NULL; + if (t->tx_pkt == tx_pkt_l3) { + t->aux->tx_pkt_l2 = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = NULL; + } else { + t->tx_pkt = t->aux->tx_pkt_orig; + t->aux->tx_pkt_orig = NULL; + } lconf->flags &= ~LCONF_FLAG_TX_BW_ACTIVE; } } diff --git a/VNFs/DPPD-PROX/log.c b/VNFs/DPPD-PROX/log.c index cd8ee002..7049a5e3 100644 --- a/VNFs/DPPD-PROX/log.c +++ b/VNFs/DPPD-PROX/log.c @@ -26,6 +26,7 @@ #include "log.h" #include "display.h" +#include "defaults.h" #include "etypes.h" #include "prox_cfg.h" @@ -140,7 +141,6 @@ static const char* lvl_to_str(int lvl, int always) } } -#define DUMP_PKT_LEN 128 static int dump_pkt(char *dst, size_t dst_size, const struct rte_mbuf *mbuf) { const struct ether_hdr *peth = rte_pktmbuf_mtod(mbuf, const struct ether_hdr *); diff --git a/VNFs/DPPD-PROX/main.c b/VNFs/DPPD-PROX/main.c index 28533c78..1c4dced9 100644 --- a/VNFs/DPPD-PROX/main.c +++ b/VNFs/DPPD-PROX/main.c @@ -46,6 +46,7 @@ #include "thread_generic.h" #include "thread_pipeline.h" #include "cqm.h" +#include "handle_master.h" #if RTE_VERSION < RTE_VERSION_NUM(1,8,0,0) #define RTE_CACHE_LINE_SIZE CACHE_LINE_SIZE @@ -111,11 +112,26 @@ static void check_mixed_normal_pipeline(void) } } -static void check_missing_rx(void) +static void check_zero_rx(void) { struct lcore_cfg *lconf = NULL; struct task_args *targ; + while (core_targ_next(&lconf, &targ, 0) == 0) { + if (targ->nb_rxports != 0) { + PROX_PANIC(task_init_flag_set(targ->task_init, TASK_FEATURE_NO_RX), + "\tCore %u task %u: rx_ports configured while mode %s does not use it\n", lconf->id, targ->id, targ->task_init->mode_str); + } + } +} + +static void check_missing_rx(void) +{ + struct lcore_cfg *lconf = NULL, *rx_lconf = NULL; + struct task_args *targ, *rx_targ = NULL; + struct prox_port_cfg *port; + uint8_t port_id, rx_port_id, ok; + while (core_targ_next(&lconf, &targ, 0) == 0) { PROX_PANIC((targ->flags & TASK_ARG_RX_RING) && targ->rx_rings[0] == 0 && !targ->tx_opt_ring_task, "Configuration Error - Core %u task %u Receiving from ring, but nobody xmitting to this ring\n", lconf->id, targ->id); @@ -124,11 +140,39 @@ static void check_missing_rx(void) "\tCore %u task %u: no rx_ports and no rx_rings configured while required by mode %s\n", lconf->id, targ->id, targ->task_init->mode_str); } } + + lconf = NULL; + while (core_targ_next(&lconf, &targ, 0) == 0) { + if (strcmp(targ->task_init->sub_mode_str, "l3") != 0) + continue; + port = find_reachable_port(targ); + if (port == NULL) + continue; + port_id = port - prox_port_cfg; + rx_lconf = NULL; + ok = 0; + plog_info("\tCore %d task %d transmitting to port %d in L3 mode\n", lconf->id, targ->id, port_id); + while (core_targ_next(&rx_lconf, &rx_targ, 0) == 0) { + for (uint8_t i = 0; i < rx_targ->nb_rxports; ++i) { + rx_port_id = rx_targ->rx_port_queue[i].port; + if ((rx_port_id == port_id) && (rx_targ->task_init->flag_features & TASK_FEATURE_L3)){ + ok = 1; + break; + } + } + if (ok == 1) { + plog_info("\tCore %d task %d has found core %d task %d receiving from port %d\n", lconf->id, targ->id, rx_lconf->id, rx_targ->id, port_id); + break; + } + } + PROX_PANIC(ok == 0, "L3 sub mode for port %d on core %d task %d, but no core/task receiving on that port\n", port_id, lconf->id, targ->id); + } } static void check_cfg_consistent(void) { check_missing_rx(); + check_zero_rx(); check_mixed_normal_pipeline(); } @@ -280,11 +324,6 @@ static const char *gen_ring_name(void) return retval; } -static int task_is_master(struct task_args *targ) -{ - return !targ->lconf; -} - struct ring_init_stats { uint32_t n_pkt_rings; uint32_t n_ctrl_rings; @@ -332,7 +371,7 @@ static struct rte_ring *get_existing_ring(uint32_t lcore_id, uint32_t task_id) return lconf->targs[task_id].rx_rings[0]; } -static void init_ring_between_tasks(struct lcore_cfg *lconf, struct task_args *starg, +static struct rte_ring *init_ring_between_tasks(struct lcore_cfg *lconf, struct task_args *starg, const struct core_task ct, uint8_t ring_idx, int idx, struct ring_init_stats *ris) { @@ -377,13 +416,15 @@ static void init_ring_between_tasks(struct lcore_cfg *lconf, struct task_args *s *dring = ring; if (lconf->id == prox_cfg.master) { ctrl_rings[ct.core*MAX_TASKS_PER_CORE + ct.task] = ring; + } else if (ct.core == prox_cfg.master) { + starg->ctrl_plane_ring = ring; } plog_info("\t\tCore %u task %u to -> core %u task %u ctrl_ring %s %p %s\n", lconf->id, starg->id, ct.core, ct.task, ct.type == CTRL_TYPE_PKT? "pkt" : "msg", ring, ring->name); ris->n_ctrl_rings++; - return; + return ring; } dtarg = &lworker->targs[ct.task]; @@ -393,7 +434,7 @@ static void init_ring_between_tasks(struct lcore_cfg *lconf, struct task_args *s /* If all the following conditions are met, the ring can be optimized away. */ - if (!task_is_master(starg) && starg->lconf->id == dtarg->lconf->id && + if (!task_is_master(starg) && !task_is_master(dtarg) && starg->lconf->id == dtarg->lconf->id && starg->nb_txrings == 1 && idx == 0 && dtarg->task && dtarg->tot_rxrings == 1 && starg->task == dtarg->task - 1) { plog_info("\t\tOptimizing away ring on core %u from task %u to task %u\n", @@ -405,7 +446,7 @@ static void init_ring_between_tasks(struct lcore_cfg *lconf, struct task_args *s dtarg->tx_opt_ring_task = starg; ris->n_opt_rings++; ++dtarg->nb_rxrings; - return; + return NULL; } int ring_created = 1; @@ -447,6 +488,7 @@ static void init_ring_between_tasks(struct lcore_cfg *lconf, struct task_args *s lconf->id, starg->id, ring_idx, ct.core, ct.task, dtarg->nb_rxrings, ring, ring->name, dtarg->nb_slave_threads); ++ris->n_pkt_rings; + return ring; } static void init_rings(void) @@ -476,6 +518,22 @@ static void init_rings(void) ris.n_pkt_rings, ris.n_ctrl_rings, ris.n_opt_rings); + + lconf = NULL; + struct prox_port_cfg *port; + while (core_targ_next(&lconf, &starg, 1) == 0) { + if ((starg->task_init) && (starg->task_init->flag_features & TASK_FEATURE_L3)) { + struct core_task ct; + ct.core = prox_cfg.master; + ct.task = 0; + ct.type = CTRL_TYPE_PKT; + struct rte_ring *rx_ring = init_ring_between_tasks(lconf, starg, ct, 0, 0, &ris); + + ct.core = lconf->id; + ct.task = starg->id;; + struct rte_ring *tx_ring = init_ring_between_tasks(lcore_cfg, lcore_cfg[prox_cfg.master].targs, ct, 0, 0, &ris); + } + } } static void shuffle_mempool(struct rte_mempool* mempool, uint32_t nb_mbuf) @@ -691,7 +749,7 @@ static void set_task_lconf(void) struct lcore_cfg *lconf; uint32_t lcore_id = -1; - while(prox_core_next(&lcore_id, 0) == 0) { + while(prox_core_next(&lcore_id, 1) == 0) { lconf = &lcore_cfg[lcore_id]; for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { lconf->targs[task_id].lconf = lconf; @@ -733,11 +791,30 @@ static void setup_all_task_structs(void) { struct lcore_cfg *lconf; uint32_t lcore_id = -1; + struct task_base *tmaster = NULL; - while(prox_core_next(&lcore_id, 0) == 0) { + while(prox_core_next(&lcore_id, 1) == 0) { lconf = &lcore_cfg[lcore_id]; for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { - lconf->tasks_all[task_id] = init_task_struct(&lconf->targs[task_id]); + if (task_is_master(&lconf->targs[task_id])) { + plog_info("\tInitializing MASTER struct for core %d task %d\n", lcore_id, task_id); + lconf->tasks_all[task_id] = init_task_struct(&lconf->targs[task_id]); + tmaster = lconf->tasks_all[task_id]; + } + } + } + PROX_PANIC(tmaster == NULL, "Can't initialize master task\n"); + lcore_id = -1; + + while(prox_core_next(&lcore_id, 1) == 0) { + lconf = &lcore_cfg[lcore_id]; + plog_info("\tInitializing struct for core %d with %d task\n", lcore_id, lconf->n_tasks_all); + for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { + if (!task_is_master(&lconf->targs[task_id])) { + plog_info("\tInitializing struct for core %d task %d\n", lcore_id, task_id); + lconf->targs[task_id].tmaster = tmaster; + lconf->tasks_all[task_id] = init_task_struct(&lconf->targs[task_id]); + } } } } diff --git a/VNFs/DPPD-PROX/msr.c b/VNFs/DPPD-PROX/msr.c index 194d4c75..8aa1e3a3 100644 --- a/VNFs/DPPD-PROX/msr.c +++ b/VNFs/DPPD-PROX/msr.c @@ -75,6 +75,6 @@ int msr_write(int lcore_id, uint64_t val, off_t offset) if (sizeof(uint64_t) != pwrite(msr_fd[lcore_id], &val, sizeof(uint64_t), offset)) { return -1; } - plog_dbg("\t\tmsr_write(core %d, offset %x, val %lx)\n", lcore_id, (int)offset, val); + // plogx_dbg("\t\tmsr_write(core %d, offset %x, val %lx)\n", lcore_id, (int)offset, val); return 0; } diff --git a/VNFs/DPPD-PROX/packet_utils.c b/VNFs/DPPD-PROX/packet_utils.c new file mode 100644 index 00000000..c22183be --- /dev/null +++ b/VNFs/DPPD-PROX/packet_utils.c @@ -0,0 +1,274 @@ +/* +// Copyright (c) 2010-2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include +#include +#include +#include "task_base.h" +#include "lconf.h" +#include "prefetch.h" +#include "log.h" +#include "handle_master.h" +#include "prox_port_cfg.h" + +#define IP4(x) x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, x >> 24 + +static inline int find_ip(struct ether_hdr_arp *pkt, uint16_t len, uint32_t *ip_dst) +{ + struct vlan_hdr *vlan_hdr; + struct ether_hdr *eth_hdr = (struct ether_hdr*)pkt; + struct ipv4_hdr *ip; + uint16_t ether_type = eth_hdr->ether_type; + uint16_t l2_len = sizeof(struct ether_hdr); + + // Unstack VLAN tags + while (((ether_type == ETYPE_8021ad) || (ether_type == ETYPE_VLAN)) && (l2_len + sizeof(struct vlan_hdr) < len)) { + vlan_hdr = (struct vlan_hdr *)((uint8_t *)pkt + l2_len); + l2_len +=4; + ether_type = vlan_hdr->eth_proto; + } + + switch (ether_type) { + case ETYPE_MPLSU: + case ETYPE_MPLSM: + // In case of MPLS, next hop MAC is based on MPLS, not destination IP + l2_len = 0; + break; + case ETYPE_IPv4: + break; + case ETYPE_EoGRE: + case ETYPE_ARP: + case ETYPE_IPv6: + l2_len = 0; + break; + default: + l2_len = 0; + plog_warn("Unsupported packet type %x - CRC might be wrong\n", ether_type); + break; + } + + if (l2_len && (l2_len + sizeof(struct ipv4_hdr) <= len)) { + struct ipv4_hdr *ip = (struct ipv4_hdr *)((uint8_t *)pkt + l2_len); + // TODO: implement LPM => replace ip_dst by next hop IP DST + *ip_dst = ip->dst_addr; + return 0; + } + return -1; +} + +int write_dst_mac(struct task_base *tbase, struct rte_mbuf *mbuf, uint32_t *ip_dst) +{ + const uint64_t hz = rte_get_tsc_hz(); + struct ether_hdr_arp *packet = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *); + struct ether_addr *mac = &packet->ether_hdr.d_addr; + + uint64_t tsc = rte_rdtsc(); + struct l3_base *l3 = &(tbase->l3); + if (l3->gw.ip) { + if (likely((l3->flags & FLAG_DST_MAC_KNOWN) && (tsc < l3->gw.arp_update_time) && (tsc < l3->gw.arp_timeout))) { + memcpy(mac, &l3->gw.mac, sizeof(struct ether_addr)); + return 0; + } else if (tsc > l3->gw.arp_update_time) { + // long time since we have sent an arp, send arp + l3->gw.arp_update_time = tsc + hz; + *ip_dst = l3->gw.ip; + return -1; + } + return -2; + } + + uint16_t len = rte_pktmbuf_pkt_len(mbuf); + if (find_ip(packet, len, ip_dst) != 0) { + return 0; + } + if (likely(l3->n_pkts < 4)) { + for (unsigned int idx = 0; idx < l3->n_pkts; idx++) { + if (*ip_dst == l3->optimized_arp_table[idx].ip) { + if ((tsc < l3->optimized_arp_table[idx].arp_update_time) && (tsc < l3->optimized_arp_table[idx].arp_timeout)) { + memcpy(mac, &l3->optimized_arp_table[idx].mac, sizeof(struct ether_addr)); + return 0; + } else if (tsc > l3->optimized_arp_table[idx].arp_update_time) { + l3->optimized_arp_table[idx].arp_update_time = tsc + hz; + return -1; + } else { + return -2; + } + } + } + l3->optimized_arp_table[l3->n_pkts].ip = *ip_dst; + l3->optimized_arp_table[l3->n_pkts].arp_update_time = tsc + hz; + l3->n_pkts++; + + if (l3->n_pkts < 4) + return -1; + + // We have ** many ** IP addresses; lets use hash table instead + for (uint32_t idx = 0; idx < l3->n_pkts; idx++) { + uint32_t ip = l3->optimized_arp_table[idx].ip; + int ret = rte_hash_add_key(l3->ip_hash, (const void *)&ip); + if (ret < 0) { + plogx_info("Unable add ip %d.%d.%d.%d in mac_hash\n", IP4(ip)); + } else { + memcpy(&l3->arp_table[ret], &l3->optimized_arp_table[idx], sizeof(struct arp_table)); + } + } + return -1; + } else { + // Find mac in lookup table. Send ARP if not found + int ret = rte_hash_lookup(l3->ip_hash, (const void *)ip_dst); + if (unlikely(ret < 0)) { + int ret = rte_hash_add_key(l3->ip_hash, (const void *)ip_dst); + if (ret < 0) { + plogx_info("Unable add ip %d.%d.%d.%d in mac_hash\n", IP4(*ip_dst)); + return -2; + } else { + l3->arp_table[ret].ip = *ip_dst; + l3->arp_table[ret].arp_update_time = tsc + hz; + } + return -1; + } else { + if ((tsc < l3->arp_table[ret].arp_update_time) && (tsc < l3->arp_table[ret].arp_timeout)) { + memcpy(mac, &l3->arp_table[ret].mac, sizeof(struct ether_addr)); + return 0; + } else if (tsc > l3->arp_table[ret].arp_update_time) { + l3->arp_table[ret].arp_update_time = tsc + hz; + return -1; + } else { + return -2; + } + } + } + return 0; +} + +void task_init_l3(struct task_base *tbase, struct task_args *targ) +{ + static char hash_name[30]; + uint32_t n_entries = MAX_ARP_ENTRIES * 4; + const int socket_id = rte_lcore_to_socket_id(targ->lconf->id); + sprintf(hash_name, "A%03d_mac_table", targ->lconf->id); + + hash_name[0]++; + + struct rte_hash_parameters hash_params = { + .name = hash_name, + .entries = n_entries, + .key_len = sizeof(uint32_t), + .hash_func = rte_hash_crc, + .hash_func_init_val = 0, + }; + tbase->l3.ip_hash = rte_hash_create(&hash_params); + PROX_PANIC(tbase->l3.ip_hash == NULL, "Failed to set up ip hash table\n"); + + tbase->l3.arp_table = (struct arp_table *)prox_zmalloc(n_entries * sizeof(struct arp_table), socket_id); + PROX_PANIC(tbase->l3.arp_table == NULL, "Failed to allocate memory for %u entries in arp table\n", n_entries); + plog_info("\tarp table, with %d entries of size %ld\n", n_entries, sizeof(struct l3_base)); + + targ->lconf->ctrl_func_p[targ->task] = handle_ctrl_plane_pkts; + targ->lconf->ctrl_timeout = freq_to_tsc(targ->ctrl_freq); + tbase->l3.gw.ip = rte_cpu_to_be_32(targ->gateway_ipv4); + tbase->flags |= TASK_L3; + tbase->l3.core_id = targ->lconf->id; + tbase->l3.task_id = targ->id; + tbase->l3.tmaster = targ->tmaster; +} + +void task_start_l3(struct task_base *tbase, struct task_args *targ) +{ + struct prox_port_cfg *port = find_reachable_port(targ); + if (port) { + tbase->l3.reachable_port_id = port - prox_port_cfg; + if (targ->local_ipv4) { + tbase->local_ipv4 = rte_be_to_cpu_32(targ->local_ipv4); + register_ip_to_ctrl_plane(tbase->l3.tmaster, tbase->local_ipv4, tbase->l3.reachable_port_id, targ->lconf->id, targ->id); + } + } +} + +void task_set_gateway_ip(struct task_base *tbase, uint32_t ip) +{ + tbase->l3.gw.ip = ip; + tbase->flags &= ~FLAG_DST_MAC_KNOWN; +} + +void task_set_local_ip(struct task_base *tbase, uint32_t ip) +{ + tbase->local_ipv4 = ip; +} + +void handle_ctrl_plane_pkts(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) +{ + uint8_t out[1]; + const uint64_t hz = rte_get_tsc_hz(); + uint32_t ip, ip_dst, idx; + int j; + uint16_t command; + struct ether_hdr_arp *hdr; + struct l3_base *l3 = &tbase->l3; + uint64_t tsc= rte_rdtsc(); + + for (j = 0; j < n_pkts; ++j) { + PREFETCH0(mbufs[j]); + } + for (j = 0; j < n_pkts; ++j) { + PREFETCH0(rte_pktmbuf_mtod(mbufs[j], void *)); + } + + for (j = 0; j < n_pkts; ++j) { + out[0] = OUT_HANDLED; + command = mbufs[j]->udata64 & 0xFFFF; + plogx_dbg("\tReceived %s mbuf %p\n", actions_string[command], mbufs[j]); + switch(command) { + case UPDATE_FROM_CTRL: + hdr = rte_pktmbuf_mtod(mbufs[j], struct ether_hdr_arp *); + ip = (mbufs[j]->udata64 >> 32) & 0xFFFFFFFF; + + if (ip == l3->gw.ip) { + // MAC address of the gateway + memcpy(&l3->gw.mac, &hdr->arp.data.sha, 6); + l3->flags |= FLAG_DST_MAC_KNOWN; + l3->gw.arp_timeout = tsc + 30 * hz; + } else if (l3->n_pkts < 4) { + // Few packets tracked - should be faster to loop through them thean using a hash table + for (idx = 0; idx < l3->n_pkts; idx++) { + ip_dst = l3->optimized_arp_table[idx].ip; + if (ip_dst == ip) + break; + } + if (idx < l3->n_pkts) { + // IP not found; this is a reply while we never asked for the request! + memcpy(&l3->optimized_arp_table[idx].mac, &(hdr->arp.data.sha), sizeof(struct ether_addr)); + l3->optimized_arp_table[idx].arp_timeout = tsc + 30 * hz; + } + } else { + int ret = rte_hash_add_key(l3->ip_hash, (const void *)&ip); + if (ret < 0) { + plogx_info("Unable add ip %d.%d.%d.%d in mac_hash\n", IP4(ip)); + } else { + memcpy(&l3->arp_table[ret].mac, &(hdr->arp.data.sha), sizeof(struct ether_addr)); + l3->arp_table[ret].arp_timeout = tsc + 30 * hz; + } + } + tx_drop(mbufs[j]); + break; + case ARP_REPLY_FROM_CTRL: + case ARP_REQ_FROM_CTRL: + out[0] = 0; + tbase->aux->tx_pkt_l2(tbase, &mbufs[j], 1, out); + break; + } + } +} diff --git a/VNFs/DPPD-PROX/packet_utils.h b/VNFs/DPPD-PROX/packet_utils.h new file mode 100644 index 00000000..0017a89e --- /dev/null +++ b/VNFs/DPPD-PROX/packet_utils.h @@ -0,0 +1,54 @@ +/* +// Copyright (c) 2010-2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "arp.h" +#include "quit.h" +#include "prox_malloc.h" +#include "defaults.h" +#include "prox_cfg.h" +#include "etypes.h" + +#define FLAG_DST_MAC_KNOWN 1 +#define MAX_ARP_ENTRIES 65536 + +struct task_base; +struct task_args; +struct arp_table { + uint64_t arp_update_time; + uint64_t arp_timeout; + uint32_t ip; + struct ether_addr mac; +}; +struct l3_base { + struct rte_ring *ctrl_plane_ring; + struct task_base *tmaster; + uint32_t flags; + uint32_t n_pkts; + uint8_t reachable_port_id; + uint8_t core_id; + uint8_t task_id; + struct arp_table gw; + struct arp_table optimized_arp_table[4]; + struct rte_hash *ip_hash; + struct arp_table *arp_table; +}; + +void task_init_l3(struct task_base *tbase, struct task_args *targ); +void task_start_l3(struct task_base *tbase, struct task_args *targ); +int write_dst_mac(struct task_base *tbase, struct rte_mbuf *mbuf, uint32_t *ip_dst); +void task_set_gateway_ip(struct task_base *tbase, uint32_t ip); +void task_set_local_ip(struct task_base *tbase, uint32_t ip); +void handle_ctrl_plane_pkts(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts); diff --git a/VNFs/DPPD-PROX/prox_args.c b/VNFs/DPPD-PROX/prox_args.c index 2703c228..fd8ea524 100644 --- a/VNFs/DPPD-PROX/prox_args.c +++ b/VNFs/DPPD-PROX/prox_args.c @@ -1063,6 +1063,15 @@ static int get_core_cfg(unsigned sindex, char *str, void *data) set_errf("Master core can only have one task\n"); return -1; } + // Initialize number of tasks to 1 for master, even if no task specified + lconf->n_tasks_all = 1; + lconf->active_task = 0; + lconf->targs[lconf->active_task].task = 0; + struct task_init* task_init = to_task_init(mode, ""); + if (task_init) { + targ->mode = task_init->mode; + } + targ->task_init = task_init; return 0; } @@ -1231,8 +1240,20 @@ static int get_core_cfg(unsigned sindex, char *str, void *data) targ->task_init = to_task_init(mode_str, sub_mode_str); if (!targ->task_init) { - set_errf("sub mode %s not supported for mode %s", sub_mode_str, mode_str); - return -1; + if (strcmp(sub_mode_str, "l3") != 0) { + set_errf("sub mode %s not supported for mode %s", sub_mode_str, mode_str); + return -1; + } + targ->task_init = to_task_init(mode_str, ""); + if (!targ->task_init) { + set_errf("sub mode %s not supported for mode %s", sub_mode_str, mode_str); + return -1; + } + } + if (strcmp(sub_mode_str, "l3") == 0) { + prox_cfg.flags |= DSF_CTRL_PLANE_ENABLED; + targ->task_init->flag_features |= TASK_FEATURE_L3; + strcpy(targ->task_init->sub_mode_str, "l3"); } return 0; } @@ -1282,9 +1303,6 @@ static int get_core_cfg(unsigned sindex, char *str, void *data) if (STR_EQ(str, "gateway ipv4")) { /* Gateway IP address used when generating */ return parse_ip(&targ->gateway_ipv4, pkey); } - if (STR_EQ(str, "number of ip")) { /* Gateway IP address used when generating */ - return parse_int(&targ->number_gen_ip, pkey); - } if (STR_EQ(str, "local ipv4")) { /* source IP address to be used for packets */ return parse_ip(&targ->local_ipv4, pkey); } diff --git a/VNFs/DPPD-PROX/prox_cfg.h b/VNFs/DPPD-PROX/prox_cfg.h index a7d0e7ea..ed54ecc5 100644 --- a/VNFs/DPPD-PROX/prox_cfg.h +++ b/VNFs/DPPD-PROX/prox_cfg.h @@ -40,6 +40,7 @@ #define DSF_DISABLE_CMT 0x00002000 /* CMT disabled */ #define DSF_LIST_TASK_MODES 0x00004000 /* list supported task modes and exit */ #define DSF_ENABLE_BYPASS 0x00008000 /* Use Multi Producer rings to enable ring bypass */ +#define DSF_CTRL_PLANE_ENABLED 0x00010000 /* ctrl plane enabled */ #define MAX_PATH_LEN 1024 diff --git a/VNFs/DPPD-PROX/prox_cksum.c b/VNFs/DPPD-PROX/prox_cksum.c index b69c06f6..9a05097e 100644 --- a/VNFs/DPPD-PROX/prox_cksum.c +++ b/VNFs/DPPD-PROX/prox_cksum.c @@ -83,26 +83,23 @@ void prox_ip_udp_cksum(struct rte_mbuf *mbuf, struct ipv4_hdr *pip, uint16_t l2_ { prox_ip_cksum(mbuf, pip, l2_len, l3_len, cksum_offload & IPV4_CKSUM); -#ifndef SOFT_CRC - if (cksum_offload & UDP_CKSUM) - mbuf->ol_flags |= PKT_TX_UDP_CKSUM; -#endif - uint32_t l4_len = rte_bswap16(pip->total_length) - l3_len; if (pip->next_proto_id == IPPROTO_UDP) { struct udp_hdr *udp = (struct udp_hdr *)(((uint8_t*)pip) + l3_len); #ifndef SOFT_CRC - if (cksum_offload & UDP_CKSUM) + if (cksum_offload & UDP_CKSUM) { + mbuf->ol_flags |= PKT_TX_UDP_CKSUM; prox_write_udp_pseudo_hdr(udp, l4_len, pip->src_addr, pip->dst_addr); - else + } else #endif prox_udp_cksum_sw(udp, l4_len, pip->src_addr, pip->dst_addr); } else if (pip->next_proto_id == IPPROTO_TCP) { struct tcp_hdr *tcp = (struct tcp_hdr *)(((uint8_t*)pip) + l3_len); #ifndef SOFT_CRC - if (cksum_offload & UDP_CKSUM) + if (cksum_offload & UDP_CKSUM) { prox_write_tcp_pseudo_hdr(tcp, l4_len, pip->src_addr, pip->dst_addr); - else + mbuf->ol_flags |= PKT_TX_UDP_CKSUM; + } else #endif prox_tcp_cksum_sw(tcp, l4_len, pip->src_addr, pip->dst_addr); } diff --git a/VNFs/DPPD-PROX/prox_port_cfg.c b/VNFs/DPPD-PROX/prox_port_cfg.c index 7e0c2c70..d9ce82d2 100644 --- a/VNFs/DPPD-PROX/prox_port_cfg.c +++ b/VNFs/DPPD-PROX/prox_port_cfg.c @@ -55,15 +55,26 @@ int prox_last_port_active(void) return ret; } +#if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1) +static int lsc_cb(__attribute__((unused)) uint8_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param, + __attribute__((unused)) void *ret_param) +#else static void lsc_cb(__attribute__((unused)) uint8_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param) +#endif { - struct rte_eth_link link; - if (RTE_ETH_EVENT_INTR_LSC != type) { +#if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1) + return -1; +#else return; +#endif } rte_atomic32_inc(&lsc); + +#if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1) + return 0; +#endif } struct prox_pktmbuf_reinit_args { diff --git a/VNFs/DPPD-PROX/prox_port_cfg.h b/VNFs/DPPD-PROX/prox_port_cfg.h index 17616187..370b0456 100644 --- a/VNFs/DPPD-PROX/prox_port_cfg.h +++ b/VNFs/DPPD-PROX/prox_port_cfg.h @@ -17,6 +17,7 @@ #ifndef _PROX_PORT_CFG_H #define _PROX_PORT_CFG_H +#include #include #include diff --git a/VNFs/DPPD-PROX/run.c b/VNFs/DPPD-PROX/run.c index 971d7148..3abdb819 100644 --- a/VNFs/DPPD-PROX/run.c +++ b/VNFs/DPPD-PROX/run.c @@ -37,6 +37,7 @@ #include "input.h" #include "input_curses.h" #include "input_conn.h" +#include "handle_master.h" static int needs_refresh; static uint64_t update_interval; @@ -127,7 +128,10 @@ static void busy_wait_until(uint64_t deadline) static void multiplexed_input_stats(uint64_t deadline) { - input_proc_until(deadline); + if (deadline) + input_proc_until(deadline); + else + input_proc(); if (needs_refresh) { needs_refresh = 0; @@ -164,6 +168,7 @@ void __attribute__((noreturn)) run(uint32_t flags) uint64_t cur_tsc; uint64_t next_update; uint64_t stop_tsc = 0; + int ret = 0; const uint64_t update_interval_threshold = usec_to_tsc(1); if (flags & DSF_LISTEN_TCP) @@ -209,20 +214,43 @@ void __attribute__((noreturn)) run(uint32_t flags) cmd_rx_tx_info(); print_warnings(); - while (stop_prox == 0) { + struct task_master *task = (struct task_master *)lcore_cfg[prox_cfg.master].tasks_all[0]; + if (handle_ctrl_plane) { + while (stop_prox == 0) { + ret = 1; + // Run ctrl plane for max 10 msec to let screen and keyboard updates + if (prox_cfg.flags & DSF_CTRL_PLANE_ENABLED) { + uint64_t ctrl_plane_update = rte_rdtsc() + msec_to_tsc(10); + while ((ret) && (rte_rdtsc() < ctrl_plane_update)) + ret = handle_ctrl_plane(lcore_cfg[prox_cfg.master].tasks_all[0], NULL, 0); + } + multiplexed_input_stats(0); + if (rte_rdtsc() < next_update) + continue; + next_update += update_interval; + stats_update(stats_cons_flags); + stats_cons_notify(); + + if (stop_tsc && rte_rdtsc() >= stop_tsc) { + stop_prox = 1; + } + } + } else { + while (stop_prox == 0) { - if (update_interval < update_interval_threshold) - busy_wait_until(next_update); - else - multiplexed_input_stats(next_update); + if (update_interval < update_interval_threshold) + busy_wait_until(next_update); + else + multiplexed_input_stats(next_update); - next_update += update_interval; + next_update += update_interval; - stats_update(stats_cons_flags); - stats_cons_notify(); + stats_update(stats_cons_flags); + stats_cons_notify(); - if (stop_tsc && rte_rdtsc() >= stop_tsc) { - stop_prox = 1; + if (stop_tsc && rte_rdtsc() >= stop_tsc) { + stop_prox = 1; + } } } diff --git a/VNFs/DPPD-PROX/rx_pkt.c b/VNFs/DPPD-PROX/rx_pkt.c index a6c1fd10..ec698d9a 100644 --- a/VNFs/DPPD-PROX/rx_pkt.c +++ b/VNFs/DPPD-PROX/rx_pkt.c @@ -24,6 +24,10 @@ #include "stats.h" #include "log.h" #include "mbuf_utils.h" +#include "prefetch.h" +#include "arp.h" +#include "tx_pkt.h" +#include "handle_master.h" #include "input.h" /* Needed for callback on dump */ /* _param version of the rx_pkt_hw functions are used to create two @@ -70,56 +74,137 @@ static void next_port_pow2(struct rx_params_hw *rx_params_hw) rx_params_hw->last_read_portid = (rx_params_hw->last_read_portid + 1) & rx_params_hw->rxport_mask; } -static uint16_t rx_pkt_hw_param(struct task_base *tbase, struct rte_mbuf ***mbufs, int multi, - void (*next)(struct rx_params_hw *rx_param_hw)) +static inline void dump_l3(struct task_base *tbase, struct rte_mbuf *mbuf) +{ + if (unlikely(tbase->aux->task_rt_dump.n_print_rx)) { + if (tbase->aux->task_rt_dump.input->reply == NULL) { + plogdx_info(mbuf, "RX: "); + } else { + struct input *input = tbase->aux->task_rt_dump.input; + char tmp[128]; + int strlen; +#if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0) + int port_id = mbuf->port; +#else + int port_id = mbuf->pkt.in_port; +#endif + strlen = snprintf(tmp, sizeof(tmp), "pktdump,%d,%d\n", port_id, + rte_pktmbuf_pkt_len(mbuf)); + input->reply(input, tmp, strlen); + input->reply(input, rte_pktmbuf_mtod(mbuf, char *), rte_pktmbuf_pkt_len(mbuf)); + input->reply(input, "\n", 1); + } + tbase->aux->task_rt_dump.n_print_rx --; + if (0 == tbase->aux->task_rt_dump.n_print_rx) { + task_base_del_rx_pkt_function(tbase, rx_pkt_dump); + } + } + if (unlikely(tbase->aux->task_rt_dump.n_trace)) { + plogdx_info(mbuf, "RX: "); + tbase->aux->task_rt_dump.n_trace--; + } +} + +static uint16_t rx_pkt_hw_param(struct task_base *tbase, struct rte_mbuf ***mbufs_ptr, int multi, + void (*next)(struct rx_params_hw *rx_param_hw), int l3) { uint8_t last_read_portid; uint16_t nb_rx; + int skip = 0; START_EMPTY_MEASSURE(); - *mbufs = tbase->ws_mbuf->mbuf[0] + + *mbufs_ptr = tbase->ws_mbuf->mbuf[0] + (RTE_ALIGN_CEIL(tbase->ws_mbuf->idx[0].prod, 2) & WS_MBUF_MASK); last_read_portid = tbase->rx_params_hw.last_read_portid; struct port_queue *pq = &tbase->rx_params_hw.rx_pq[last_read_portid]; - nb_rx = rx_pkt_hw_port_queue(pq, *mbufs, multi); + nb_rx = rx_pkt_hw_port_queue(pq, *mbufs_ptr, multi); next(&tbase->rx_params_hw); + if (l3) { + struct rte_mbuf **mbufs = *mbufs_ptr; + int i; + struct ether_hdr_arp *hdr[MAX_PKT_BURST]; + for (i = 0; i < nb_rx; i++) { + PREFETCH0(mbufs[i]); + } + for (i = 0; i < nb_rx; i++) { + hdr[i] = rte_pktmbuf_mtod(mbufs[i], struct ether_hdr_arp *); + PREFETCH0(hdr[i]); + } + for (i = 0; i < nb_rx; i++) { + if (unlikely(hdr[i]->ether_hdr.ether_type == ETYPE_ARP)) { + dump_l3(tbase, mbufs[i]); + tx_ring(tbase, tbase->l3.ctrl_plane_ring, ARP_TO_CTRL, mbufs[i]); + skip++; + } else if (unlikely(skip)) { + mbufs[i - skip] = mbufs[i]; + } + } + } + + if (skip) + TASK_STATS_ADD_DROP_HANDLED(&tbase->aux->stats, skip); if (likely(nb_rx > 0)) { TASK_STATS_ADD_RX(&tbase->aux->stats, nb_rx); - return nb_rx; + return nb_rx - skip; } TASK_STATS_ADD_IDLE(&tbase->aux->stats, rte_rdtsc() - cur_tsc); return 0; } -static inline uint16_t rx_pkt_hw1_param(struct task_base *tbase, struct rte_mbuf ***mbufs, int multi) +static inline uint16_t rx_pkt_hw1_param(struct task_base *tbase, struct rte_mbuf ***mbufs_ptr, int multi, int l3) { uint16_t nb_rx, n; + int skip = 0; START_EMPTY_MEASSURE(); - *mbufs = tbase->ws_mbuf->mbuf[0] + + *mbufs_ptr = tbase->ws_mbuf->mbuf[0] + (RTE_ALIGN_CEIL(tbase->ws_mbuf->idx[0].prod, 2) & WS_MBUF_MASK); nb_rx = rte_eth_rx_burst(tbase->rx_params_hw1.rx_pq.port, tbase->rx_params_hw1.rx_pq.queue, - *mbufs, MAX_PKT_BURST); + *mbufs_ptr, MAX_PKT_BURST); if (multi) { n = nb_rx; while ((n != 0) && (MAX_PKT_BURST - nb_rx >= MIN_PMD_RX)) { n = rte_eth_rx_burst(tbase->rx_params_hw1.rx_pq.port, tbase->rx_params_hw1.rx_pq.queue, - *mbufs + nb_rx, MIN_PMD_RX); + *mbufs_ptr + nb_rx, MIN_PMD_RX); nb_rx += n; PROX_PANIC(nb_rx > 64, "Received %d packets while expecting maximum %d\n", n, MIN_PMD_RX); } } + if (l3) { + struct rte_mbuf **mbufs = *mbufs_ptr; + int i; + struct ether_hdr_arp *hdr[MAX_PKT_BURST]; + for (i = 0; i < nb_rx; i++) { + PREFETCH0(mbufs[i]); + } + for (i = 0; i < nb_rx; i++) { + hdr[i] = rte_pktmbuf_mtod(mbufs[i], struct ether_hdr_arp *); + PREFETCH0(hdr[i]); + } + for (i = 0; i < nb_rx; i++) { + if (unlikely(hdr[i]->ether_hdr.ether_type == ETYPE_ARP)) { + dump_l3(tbase, mbufs[i]); + tx_ring(tbase, tbase->l3.ctrl_plane_ring, ARP_TO_CTRL, mbufs[i]); + skip++; + } else if (unlikely(skip)) { + mbufs[i - skip] = mbufs[i]; + } + } + } + + if (skip) + TASK_STATS_ADD_DROP_HANDLED(&tbase->aux->stats, skip); if (likely(nb_rx > 0)) { TASK_STATS_ADD_RX(&tbase->aux->stats, nb_rx); - return nb_rx; + return nb_rx - skip; } TASK_STATS_ADD_IDLE(&tbase->aux->stats, rte_rdtsc() - cur_tsc); return 0; @@ -127,36 +212,66 @@ static inline uint16_t rx_pkt_hw1_param(struct task_base *tbase, struct rte_mbuf uint16_t rx_pkt_hw(struct task_base *tbase, struct rte_mbuf ***mbufs) { - return rx_pkt_hw_param(tbase, mbufs, 0, next_port); + return rx_pkt_hw_param(tbase, mbufs, 0, next_port, 0); } uint16_t rx_pkt_hw_pow2(struct task_base *tbase, struct rte_mbuf ***mbufs) { - return rx_pkt_hw_param(tbase, mbufs, 0, next_port_pow2); + return rx_pkt_hw_param(tbase, mbufs, 0, next_port_pow2, 0); } uint16_t rx_pkt_hw1(struct task_base *tbase, struct rte_mbuf ***mbufs) { - return rx_pkt_hw1_param(tbase, mbufs, 0); + return rx_pkt_hw1_param(tbase, mbufs, 0, 0); } uint16_t rx_pkt_hw_multi(struct task_base *tbase, struct rte_mbuf ***mbufs) { - return rx_pkt_hw_param(tbase, mbufs, 1, next_port); + return rx_pkt_hw_param(tbase, mbufs, 1, next_port, 0); } uint16_t rx_pkt_hw_pow2_multi(struct task_base *tbase, struct rte_mbuf ***mbufs) { - return rx_pkt_hw_param(tbase, mbufs, 1, next_port_pow2); + return rx_pkt_hw_param(tbase, mbufs, 1, next_port_pow2, 0); } uint16_t rx_pkt_hw1_multi(struct task_base *tbase, struct rte_mbuf ***mbufs) { - return rx_pkt_hw1_param(tbase, mbufs, 1); + return rx_pkt_hw1_param(tbase, mbufs, 1, 0); +} + +uint16_t rx_pkt_hw_l3(struct task_base *tbase, struct rte_mbuf ***mbufs) +{ + return rx_pkt_hw_param(tbase, mbufs, 0, next_port, 1); +} + +uint16_t rx_pkt_hw_pow2_l3(struct task_base *tbase, struct rte_mbuf ***mbufs) +{ + return rx_pkt_hw_param(tbase, mbufs, 0, next_port_pow2, 1); +} + +uint16_t rx_pkt_hw1_l3(struct task_base *tbase, struct rte_mbuf ***mbufs) +{ + return rx_pkt_hw1_param(tbase, mbufs, 0, 1); +} + +uint16_t rx_pkt_hw_multi_l3(struct task_base *tbase, struct rte_mbuf ***mbufs) +{ + return rx_pkt_hw_param(tbase, mbufs, 1, next_port, 1); +} + +uint16_t rx_pkt_hw_pow2_multi_l3(struct task_base *tbase, struct rte_mbuf ***mbufs) +{ + return rx_pkt_hw_param(tbase, mbufs, 1, next_port_pow2, 1); +} + +uint16_t rx_pkt_hw1_multi_l3(struct task_base *tbase, struct rte_mbuf ***mbufs) +{ + return rx_pkt_hw1_param(tbase, mbufs, 1, 1); } /* The following functions implement ring access */ -static uint16_t ring_deq(struct rte_ring *r, struct rte_mbuf **mbufs) +uint16_t ring_deq(struct rte_ring *r, struct rte_mbuf **mbufs) { void **v_mbufs = (void **)mbufs; #ifdef BRAS_RX_BULK @@ -299,7 +414,7 @@ uint16_t rx_pkt_dump(struct task_base *tbase, struct rte_mbuf ***mbufs) if (tbase->aux->task_rt_dump.input->reply == NULL) { for (uint32_t i = 0; i < n_dump; ++i) { - plogd_info((*mbufs)[i], "RX: "); + plogdx_info((*mbufs)[i], "RX: "); } } else { @@ -336,19 +451,20 @@ uint16_t rx_pkt_dump(struct task_base *tbase, struct rte_mbuf ***mbufs) uint16_t rx_pkt_trace(struct task_base *tbase, struct rte_mbuf ***mbufs) { + tbase->aux->task_rt_dump.cur_trace = 0; uint16_t ret = call_prev_rx_pkt(tbase, mbufs); if (ret) { uint32_t n_trace = tbase->aux->task_rt_dump.n_trace; n_trace = ret < n_trace? ret : n_trace; - tbase->aux->task_rt_dump.cur_trace = n_trace; for (uint32_t i = 0; i < n_trace; ++i) { uint8_t *pkt = rte_pktmbuf_mtod((*mbufs)[i], uint8_t *); - rte_memcpy(tbase->aux->task_rt_dump.pkt_cpy[i], pkt, sizeof(tbase->aux->task_rt_dump.pkt_cpy[i])); - tbase->aux->task_rt_dump.pkt_cpy_len[i] = rte_pktmbuf_pkt_len((*mbufs)[i]); - tbase->aux->task_rt_dump.pkt_mbuf_addr[i] = (*mbufs)[i]; + rte_memcpy(tbase->aux->task_rt_dump.pkt_cpy[tbase->aux->task_rt_dump.cur_trace + i], pkt, sizeof(tbase->aux->task_rt_dump.pkt_cpy[i])); + tbase->aux->task_rt_dump.pkt_cpy_len[tbase->aux->task_rt_dump.cur_trace + i] = rte_pktmbuf_pkt_len((*mbufs)[i]); + tbase->aux->task_rt_dump.pkt_mbuf_addr[tbase->aux->task_rt_dump.cur_trace + i] = (*mbufs)[i]; } + tbase->aux->task_rt_dump.cur_trace += n_trace; tbase->aux->task_rt_dump.n_trace -= n_trace; /* Unset by TX when n_trace = 0 */ diff --git a/VNFs/DPPD-PROX/rx_pkt.h b/VNFs/DPPD-PROX/rx_pkt.h index 57b948e2..6d8f412c 100644 --- a/VNFs/DPPD-PROX/rx_pkt.h +++ b/VNFs/DPPD-PROX/rx_pkt.h @@ -21,10 +21,14 @@ struct rte_mbuf; struct task_base; +struct rte_ring; uint16_t rx_pkt_hw(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_hw_pow2(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_hw1(struct task_base *tbase, struct rte_mbuf ***mbufs); +uint16_t rx_pkt_hw_l3(struct task_base *tbase, struct rte_mbuf ***mbufs); +uint16_t rx_pkt_hw_pow2_l3(struct task_base *tbase, struct rte_mbuf ***mbufs); +uint16_t rx_pkt_hw1_l3(struct task_base *tbase, struct rte_mbuf ***mbufs); /* The _multi variation of the function is used to work-around the problem with QoS, multi-seg mbufs and vector PMD. When vector @@ -33,6 +37,9 @@ uint16_t rx_pkt_hw1(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_hw_multi(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_hw_pow2_multi(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_hw1_multi(struct task_base *tbase, struct rte_mbuf ***mbufs); +uint16_t rx_pkt_hw_multi_l3(struct task_base *tbase, struct rte_mbuf ***mbufs); +uint16_t rx_pkt_hw_pow2_multi_l3(struct task_base *tbase, struct rte_mbuf ***mbufs); +uint16_t rx_pkt_hw1_multi_l3(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_sw(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_sw_pow2(struct task_base *tbase, struct rte_mbuf ***mbufs); @@ -45,5 +52,6 @@ uint16_t rx_pkt_distr(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_bw(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_tsc(struct task_base *tbase, struct rte_mbuf ***mbufs); uint16_t rx_pkt_all(struct task_base *tbase, struct rte_mbuf ***mbufs); +uint16_t ring_deq(struct rte_ring *r, struct rte_mbuf **mbufs); #endif /* _RX_PKT_H_ */ diff --git a/VNFs/DPPD-PROX/stats_core.c b/VNFs/DPPD-PROX/stats_core.c index 845399e3..34a9f747 100644 --- a/VNFs/DPPD-PROX/stats_core.c +++ b/VNFs/DPPD-PROX/stats_core.c @@ -262,7 +262,7 @@ void stats_lcore_post_proc(void) ls->cmt_bytes = ls->cmt_data * scm->rdt_features.upscaling_factor; lss->mbm_tot_bytes = ls->mbm_tot * scm->rdt_features.upscaling_factor; lss->mbm_loc_bytes = ls->mbm_loc * scm->rdt_features.upscaling_factor; - plogx_dbg("cache[core %d] = %ld\n", ls->lcore_id, ls->cmt_bytes); + //plogx_dbg("cache[core %d] = %ld\n", ls->lcore_id, ls->cmt_bytes); } } for (uint8_t i = 0; i < scm->n_lcore_stats; ++i) { diff --git a/VNFs/DPPD-PROX/task_base.h b/VNFs/DPPD-PROX/task_base.h index b2fab2fc..62841e96 100644 --- a/VNFs/DPPD-PROX/task_base.h +++ b/VNFs/DPPD-PROX/task_base.h @@ -25,8 +25,9 @@ #include "defaults.h" #include "prox_globals.h" #include "stats_task.h" +#include "packet_utils.h" -// runtime_flags 8 bits only +// runtime_flags 16 bits only #define TASK_MPLS_TAGGING 0x0001 #define TASK_ROUTING 0x0002 #define TASK_CLASSIFY 0x0004 @@ -34,6 +35,7 @@ #define TASK_MARK 0x0020 #define TASK_FP_HANDLE_ARP 0x0040 #define TASK_TX_CRC 0x0080 +#define TASK_L3 0x0100 // flag_features 64 bits #define TASK_FEATURE_ROUTING 0x0001 @@ -52,6 +54,7 @@ #define TASK_FEATURE_LUT_QINQ_HASH 0x4000 #define TASK_FEATURE_RX_ALL 0x8000 #define TASK_MULTIPLE_MAC 0x10000 +#define TASK_FEATURE_L3 0x20000 #define FLAG_TX_FLUSH 0x01 #define FLAG_NEVER_FLUSH 0x02 @@ -133,7 +136,7 @@ struct task_rt_dump { uint32_t n_trace; uint32_t cur_trace; void *pkt_mbuf_addr[MAX_RING_BURST]; /* To track reordering */ - uint8_t pkt_cpy[MAX_RING_BURST][128]; + uint8_t pkt_cpy[MAX_RING_BURST][DUMP_PKT_LEN]; uint16_t pkt_cpy_len[MAX_RING_BURST]; }; @@ -164,6 +167,7 @@ struct task_base_aux { uint32_t rx_bucket[MAX_RING_BURST + 1]; uint32_t tx_bucket[MAX_RING_BURST + 1]; + int (*tx_pkt_l2)(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out); int (*tx_pkt_orig)(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out); int (*tx_pkt_hw)(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out); uint16_t (*tx_pkt_try)(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts); @@ -174,7 +178,7 @@ struct task_base_aux { }; /* The task_base is accessed for _all_ task types. In case - no debugging is needed, it has been optimized to fit + no debugging or l3 is needed, it has been optimized to fit into a single cache line to minimize cache pollution */ struct task_base { int (*handle_bulk)(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts); @@ -200,6 +204,8 @@ struct task_base { struct tx_params_sw tx_params_sw; struct tx_params_hw_sw tx_params_hw_sw; }; + struct l3_base l3; + uint32_t local_ipv4; } __attribute__((packed)) __rte_cache_aligned; static void task_base_add_rx_pkt_function(struct task_base *tbase, rx_pkt_func to_add) diff --git a/VNFs/DPPD-PROX/task_init.c b/VNFs/DPPD-PROX/task_init.c index 6d9c7b3d..3af0db2a 100644 --- a/VNFs/DPPD-PROX/task_init.c +++ b/VNFs/DPPD-PROX/task_init.c @@ -38,7 +38,7 @@ LIST_HEAD(,task_init) head; void reg_task(struct task_init* t) { - PROX_PANIC(t->handle == NULL, "No handle function specified for task with name %d\n", t->mode); + // PROX_PANIC(t->handle == NULL, "No handle function specified for task with name %d\n", t->mode); if (t->thread_x == NULL) t->thread_x = thread_generic; @@ -70,6 +70,11 @@ static int compare_strcmp(const void *a, const void *b) return strcmp(*(const char * const *)a, *(const char * const *)b); } +int task_is_master(struct task_args *targ) +{ + return (targ->lconf->id == prox_cfg.master); +} + void tasks_list(void) { struct task_init *cur_t; @@ -169,13 +174,19 @@ static size_t init_rx_tx_rings_ports(struct task_args *targ, struct task_base *t } else { if (targ->nb_rxports == 1) { - tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw1_multi : rx_pkt_hw1; + if (targ->task_init->flag_features & TASK_FEATURE_L3) + tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw1_multi_l3 : rx_pkt_hw1_l3; + else + tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw1_multi : rx_pkt_hw1; tbase->rx_params_hw1.rx_pq.port = targ->rx_port_queue[0].port; tbase->rx_params_hw1.rx_pq.queue = targ->rx_port_queue[0].queue; } else { PROX_ASSERT((targ->nb_rxports != 0) || (targ->task_init->flag_features & TASK_FEATURE_NO_RX)); - tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw_multi : rx_pkt_hw; + if (targ->task_init->flag_features & TASK_FEATURE_L3) + tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw_multi_l3 : rx_pkt_hw_l3; + else + tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw_multi : rx_pkt_hw; tbase->rx_params_hw.nb_rxports = targ->nb_rxports; tbase->rx_params_hw.rx_pq = (struct port_queue *)(((uint8_t *)tbase) + offset); offset += sizeof(struct port_queue) * tbase->rx_params_hw.nb_rxports; @@ -185,7 +196,10 @@ static size_t init_rx_tx_rings_ports(struct task_args *targ, struct task_base *t } if (rte_is_power_of_2(targ->nb_rxports)) { - tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw_pow2_multi : rx_pkt_hw_pow2; + if (targ->task_init->flag_features & TASK_FEATURE_L3) + tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw_pow2_multi_l3 : rx_pkt_hw_pow2_l3; + else + tbase->rx_pkt = (targ->task_init->flag_features & TASK_FEATURE_MULTI_RX)? rx_pkt_hw_pow2_multi : rx_pkt_hw_pow2; tbase->rx_params_hw.rxport_mask = targ->nb_rxports - 1; } } @@ -336,6 +350,13 @@ struct task_base *init_task_struct(struct task_args *targ) offset = init_rx_tx_rings_ports(targ, tbase, offset); tbase->aux = (struct task_base_aux *)(((uint8_t *)tbase) + offset); + if ((targ->nb_txrings != 0) || (targ->nb_txports != 0)) { + if (targ->task_init->flag_features & TASK_FEATURE_L3) { + tbase->aux->tx_pkt_l2 = tbase->tx_pkt; + tbase->tx_pkt = tx_pkt_l3; + } + } + if (targ->task_init->flag_features & TASK_FEATURE_RX_ALL) { task_base_add_rx_pkt_function(tbase, rx_pkt_all); tbase->aux->all_mbufs = prox_zmalloc(MAX_RX_PKT_ALL * sizeof(* tbase->aux->all_mbufs), task_socket); @@ -348,6 +369,15 @@ struct task_base *init_task_struct(struct task_args *targ) tbase->handle_bulk = t->handle; + if (targ->task_init->flag_features & TASK_FEATURE_L3) { + plog_info("\tTask configured in L3 mode\n"); + tbase->l3.ctrl_plane_ring = targ->ctrl_plane_ring; + } + if ((targ->nb_txrings != 0) || (targ->nb_txports != 0)) { + if (targ->task_init->flag_features & TASK_FEATURE_L3) + task_init_l3(tbase, targ); + } + targ->tbase = tbase; if (t->init) { t->init(tbase, targ); @@ -372,8 +402,12 @@ struct task_base *init_task_struct(struct task_args *targ) struct task_args *find_reachable_task_sending_to_port(struct task_args *from) { - if (!from->nb_txrings) - return from; + if (!from->nb_txrings) { + if (from->tx_port_queue[0].port != OUT_DISCARD) + return from; + else + return NULL; + } struct core_task ct; struct task_args *dtarg, *ret; diff --git a/VNFs/DPPD-PROX/task_init.h b/VNFs/DPPD-PROX/task_init.h index e1f5ce1c..86a9521c 100644 --- a/VNFs/DPPD-PROX/task_init.h +++ b/VNFs/DPPD-PROX/task_init.h @@ -124,12 +124,12 @@ struct task_args { uint8_t nb_rxports; uint32_t byte_offset; uint32_t gateway_ipv4; - uint32_t number_gen_ip; uint32_t local_ipv4; uint32_t remote_ipv4; struct ipv6_addr local_ipv6; /* For IPv6 Tunnel, it's the local tunnel endpoint address */ struct rte_ring *rx_rings[MAX_RINGS_PER_TASK]; struct rte_ring *tx_rings[MAX_RINGS_PER_TASK]; + struct rte_ring *ctrl_plane_ring; uint32_t tot_n_txrings_inited; struct ether_addr edaddr; struct ether_addr esaddr; @@ -223,6 +223,10 @@ struct task_args { struct rte_hash *private_ip_port_hash; struct rte_hash *private_ip_hash; struct private_ip_info *private_ip_info; + struct rte_ring **ctrl_rx_rings; + struct rte_ring **ctrl_tx_rings; + int n_ctrl_rings; + struct task_base *tmaster; }; /* Return the first port that is reachable through the task. If the @@ -234,6 +238,7 @@ struct prox_port_cfg *find_reachable_port(struct task_args *from); struct task_base *init_task_struct(struct task_args *targ); struct task_init *to_task_init(const char *mode_str, const char *sub_mode_str); void tasks_list(void); +int task_is_master(struct task_args *targ); void reg_task(struct task_init* t); diff --git a/VNFs/DPPD-PROX/tx_pkt.c b/VNFs/DPPD-PROX/tx_pkt.c index c6f6010c..9ada51ca 100644 --- a/VNFs/DPPD-PROX/tx_pkt.c +++ b/VNFs/DPPD-PROX/tx_pkt.c @@ -25,6 +25,7 @@ #include "prox_assert.h" #include "log.h" #include "mbuf_utils.h" +#include "handle_master.h" static void buf_pkt_single(struct task_base *tbase, struct rte_mbuf *mbuf, const uint8_t out) { @@ -49,9 +50,40 @@ static inline void buf_pkt_all(struct task_base *tbase, struct rte_mbuf **mbufs, } #define MAX_PMD_TX 32 +int tx_pkt_l3(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out) +{ + uint32_t ip_dst; + int first = 0, ret, ok = 0, rc; + const struct port_queue *port_queue = &tbase->tx_params_hw.tx_port_queue[0]; + + for (int j = 0; j < n_pkts; j++) { + if ((out) && (out[j] >= OUT_HANDLED)) + continue; + if (unlikely((rc = write_dst_mac(tbase, mbufs[j], &ip_dst)) < 0)) { + if (j - first) { + ret = tbase->aux->tx_pkt_l2(tbase, mbufs + first, j - first, out); + ok += ret; + } + first = j + 1; + if (rc == -1) { + mbufs[j]->port = tbase->l3.reachable_port_id; + tx_ring_cti(tbase, tbase->l3.ctrl_plane_ring, REQ_MAC_TO_CTRL, mbufs[j], tbase->l3.core_id, tbase->l3.task_id, ip_dst); + } else if (rc == -2) { + tx_drop(mbufs[j]); + TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1); + } + } + } + if (n_pkts - first) { + ret = tbase->aux->tx_pkt_l2(tbase, mbufs + first, n_pkts - first, out); + ok += ret; + } + return ok; +} + /* The following help functions also report stats. Therefore we need to pass the task_base struct. */ -static inline int txhw_drop(const struct port_queue *port_queue, struct rte_mbuf **mbufs, uint16_t n_pkts, __attribute__((unused)) struct task_base *tbase) +static inline int txhw_drop(const struct port_queue *port_queue, struct rte_mbuf **mbufs, uint16_t n_pkts, struct task_base *tbase) { uint16_t ntx; int ret; @@ -63,10 +95,11 @@ static inline int txhw_drop(const struct port_queue *port_queue, struct rte_mbuf } else { ntx = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, n_pkts); } - TASK_STATS_ADD_TX(&tbase->aux->stats, ntx); + ret = n_pkts - ntx; if (ntx < n_pkts) { + plog_dbg("Failed to send %d packets from %p\n", ret, mbufs[0]); TASK_STATS_ADD_DROP_TX_FAIL(&tbase->aux->stats, n_pkts - ntx); if (tbase->tx_pkt == tx_pkt_bw) { uint32_t drop_bytes = 0; @@ -85,13 +118,12 @@ static inline int txhw_drop(const struct port_queue *port_queue, struct rte_mbuf return ret; } -static inline int txhw_no_drop(const struct port_queue *port_queue, struct rte_mbuf **mbufs, uint16_t n_pkts, __attribute__((unused)) struct task_base *tbase) +static inline int txhw_no_drop(const struct port_queue *port_queue, struct rte_mbuf **mbufs, uint16_t n_pkts, struct task_base *tbase) { uint16_t ret; uint16_t n = n_pkts; TASK_STATS_ADD_TX(&tbase->aux->stats, n_pkts); - do { ret = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, n_pkts); mbufs += ret; @@ -265,11 +297,11 @@ uint16_t tx_try_sw1(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n uint16_t tx_try_hw1(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) { - const struct port_queue *port_queue = &tbase->tx_params_hw.tx_port_queue[0]; const int bulk_size = 64; uint16_t ret = bulk_size, n_bulks, sent = 0; n_bulks = n_pkts >> __builtin_ctz(bulk_size); + const struct port_queue *port_queue = &tbase->tx_params_hw.tx_port_queue[0]; for (int i = 0; i < n_bulks; i++) { ret = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, bulk_size); mbufs += ret; @@ -541,59 +573,91 @@ int tx_pkt_sw(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, return ret; } +static inline void trace_one_rx_pkt(struct task_base *tbase, struct rte_mbuf *mbuf) +{ + struct rte_mbuf tmp; + /* For each packet being transmitted, find which + buffer represent the packet as it was before + processing. */ + uint32_t j = 0; + uint32_t len = sizeof(tbase->aux->task_rt_dump.pkt_mbuf_addr)/sizeof(tbase->aux->task_rt_dump.pkt_mbuf_addr[0]); + for (;j < len; ++j) { + if (tbase->aux->task_rt_dump.pkt_mbuf_addr[j] == mbuf) + break; + } + if (j != len) { +#if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0) + tmp.data_off = 0; +#endif + rte_pktmbuf_data_len(&tmp) = tbase->aux->task_rt_dump.pkt_cpy_len[j]; + rte_pktmbuf_pkt_len(&tmp) = tbase->aux->task_rt_dump.pkt_cpy_len[j]; + tmp.buf_addr = tbase->aux->task_rt_dump.pkt_cpy[j]; + plogdx_info(&tmp, "Trace RX: "); + } +} + +static inline void trace_one_tx_pkt(struct task_base *tbase, struct rte_mbuf *mbuf, uint8_t *out, uint32_t i) +{ + if (out) { + switch(out[i]) { + case 0xFE: + plogdx_info(mbuf, "Handled: "); + break; + case 0xFF: + plogdx_info(mbuf, "Dropped: "); + break; + default: + plogdx_info(mbuf, "TX[%d]: ", out[i]); + break; + } + } else if (tbase->aux->tx_pkt_orig == tx_pkt_drop_all) { + plogdx_info(mbuf, "Dropped: "); + } else + plogdx_info(mbuf, "TX[0]: "); +} + +static void unset_trace(struct task_base *tbase) +{ + if (0 == tbase->aux->task_rt_dump.n_trace) { + if (tbase->tx_pkt == tx_pkt_l3) { + tbase->aux->tx_pkt_l2 = tbase->aux->tx_pkt_orig; + tbase->aux->tx_pkt_orig = NULL; + } else { + tbase->tx_pkt = tbase->aux->tx_pkt_orig; + tbase->aux->tx_pkt_orig = NULL; + } + tbase->aux->task_rt_dump.cur_trace = 0; + task_base_del_rx_pkt_function(tbase, rx_pkt_trace); + } +} + int tx_pkt_trace(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out) { int ret = 0; if (tbase->aux->task_rt_dump.cur_trace == 0) { // No packet received since dumping... - // So the transmitted packets should not be linked to received packets tbase->aux->task_rt_dump.n_print_tx = tbase->aux->task_rt_dump.n_trace; - tbase->aux->task_rt_dump.n_trace = 0; - task_base_del_rx_pkt_function(tbase, rx_pkt_trace); - return tx_pkt_dump(tbase, mbufs, n_pkts, out); + if (tbase->aux->task_rt_dump.n_trace < n_pkts) { + tbase->aux->task_rt_dump.n_trace = 0; + tbase->aux->task_rt_dump.cur_trace = 0; + task_base_del_rx_pkt_function(tbase, rx_pkt_trace); + } else { + tbase->aux->task_rt_dump.n_trace -= n_pkts; + } + ret = tx_pkt_dump(tbase, mbufs, n_pkts, out); + tbase->aux->task_rt_dump.n_print_tx = 0; + return ret; } plog_info("Tracing %d pkts\n", tbase->aux->task_rt_dump.cur_trace); + uint32_t cur_trace = (n_pkts < tbase->aux->task_rt_dump.cur_trace) ? n_pkts: tbase->aux->task_rt_dump.cur_trace; + for (uint32_t i = 0; i < cur_trace; ++i) { + trace_one_rx_pkt(tbase, mbufs[i]); + trace_one_tx_pkt(tbase, mbufs[i], out, i); - for (uint32_t i = 0; i < tbase->aux->task_rt_dump.cur_trace; ++i) { - struct rte_mbuf tmp; - /* For each packet being transmitted, find which - buffer represent the packet as it was before - processing. */ - uint32_t j = 0; - uint32_t len = sizeof(tbase->aux->task_rt_dump.pkt_mbuf_addr)/sizeof(tbase->aux->task_rt_dump.pkt_mbuf_addr[0]); - for (;j < len; ++j) { - if (tbase->aux->task_rt_dump.pkt_mbuf_addr[j] == mbufs[i]) - break; - } - if (j == len) { - plog_info("Trace RX: missing!\n"); - } - else { -#if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0) - tmp.data_off = 0; -#endif - rte_pktmbuf_data_len(&tmp) = tbase->aux->task_rt_dump.pkt_cpy_len[j]; - rte_pktmbuf_pkt_len(&tmp) = tbase->aux->task_rt_dump.pkt_cpy_len[j]; - tmp.buf_addr = tbase->aux->task_rt_dump.pkt_cpy[j]; - plogd_info(&tmp, "Trace RX: "); - } - - if (out) { - if (out[i] != 0xFF) - plogd_info(mbufs[i], "Trace TX[%d]: ", out[i]); - else - plogd_info(mbufs[i], "Trace Dropped: "); - } else - plogd_info(mbufs[i], "Trace TX: "); } ret = tbase->aux->tx_pkt_orig(tbase, mbufs, n_pkts, out); - /* Unset by TX when n_trace = 0 */ - if (0 == tbase->aux->task_rt_dump.n_trace) { - tbase->tx_pkt = tbase->aux->tx_pkt_orig; - tbase->aux->tx_pkt_orig = NULL; - task_base_del_rx_pkt_function(tbase, rx_pkt_trace); - } + unset_trace(tbase); return ret; } @@ -604,18 +668,33 @@ int tx_pkt_dump(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkt n_dump = n_pkts < n_dump? n_pkts : n_dump; for (uint32_t i = 0; i < n_dump; ++i) { - if (out) - plogd_info(mbufs[i], "TX[%d]: ", out[i]); - else - plogd_info(mbufs[i], "TX: "); + if (out) { + switch (out[i]) { + case 0xFE: + plogdx_info(mbufs[i], "Handled: "); + break; + case 0xFF: + plogdx_info(mbufs[i], "Dropped: "); + break; + default: + plogdx_info(mbufs[i], "TX[%d]: ", out[i]); + break; + } + } else + plogdx_info(mbufs[i], "TX: "); } tbase->aux->task_rt_dump.n_print_tx -= n_dump; ret = tbase->aux->tx_pkt_orig(tbase, mbufs, n_pkts, out); if (0 == tbase->aux->task_rt_dump.n_print_tx) { - tbase->tx_pkt = tbase->aux->tx_pkt_orig; - tbase->aux->tx_pkt_orig = NULL; + if (tbase->tx_pkt == tx_pkt_l3) { + tbase->aux->tx_pkt_l2 = tbase->aux->tx_pkt_orig; + tbase->aux->tx_pkt_orig = NULL; + } else { + tbase->tx_pkt = tbase->aux->tx_pkt_orig; + tbase->aux->tx_pkt_orig = NULL; + } } return ret; } @@ -663,3 +742,45 @@ int tx_pkt_drop_all(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n } return n_pkts; } + +static inline int tx_ring_all(struct task_base *tbase, struct rte_ring *ring, uint16_t command, struct rte_mbuf *mbuf, uint8_t core_id, uint8_t task_id, uint32_t ip) +{ + if (tbase->aux->task_rt_dump.cur_trace) { + trace_one_rx_pkt(tbase, mbuf); + } + mbuf->udata64 = ((uint64_t)ip << 32) | (core_id << 16) | (task_id << 8) | command; + return rte_ring_enqueue(ring, mbuf); +} + +void tx_ring_cti(struct task_base *tbase, struct rte_ring *ring, uint16_t command, struct rte_mbuf *mbuf, uint8_t core_id, uint8_t task_id, uint32_t ip) +{ + plogx_dbg("\tSending command %s with ip %x to ring %p using mbuf %p, core %d and task %d - ring size now %d\n", actions_string[command], ip, ring, mbuf, core_id, task_id, rte_ring_free_count(ring)); + int ret = tx_ring_all(tbase, ring, command, mbuf, core_id, task_id, ip); + if (unlikely(ret != 0)) { + plogx_dbg("\tFail to send command %s with ip %x to ring %p using mbuf %p, core %d and task %d - ring size now %d\n", actions_string[command], ip, ring, mbuf, core_id, task_id, rte_ring_free_count(ring)); + TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1); + rte_pktmbuf_free(mbuf); + } +} + +void tx_ring_ip(struct task_base *tbase, struct rte_ring *ring, uint16_t command, struct rte_mbuf *mbuf, uint32_t ip) +{ + plogx_dbg("\tSending command %s with ip %x to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ip, ring, mbuf, rte_ring_free_count(ring)); + int ret = tx_ring_all(tbase, ring, command, mbuf, 0, 0, ip); + if (unlikely(ret != 0)) { + plogx_dbg("\tFail to send command %s with ip %x to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ip, ring, mbuf, rte_ring_free_count(ring)); + TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1); + rte_pktmbuf_free(mbuf); + } +} + +void tx_ring(struct task_base *tbase, struct rte_ring *ring, uint16_t command, struct rte_mbuf *mbuf) +{ + plogx_dbg("\tSending command %s to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ring, mbuf, rte_ring_free_count(ring)); + int ret = tx_ring_all(tbase, ring, command, mbuf, 0, 0, 0); + if (unlikely(ret != 0)) { + plogx_dbg("\tFail to send command %s to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ring, mbuf, rte_ring_free_count(ring)); + TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1); + rte_pktmbuf_free(mbuf); + } +} diff --git a/VNFs/DPPD-PROX/tx_pkt.h b/VNFs/DPPD-PROX/tx_pkt.h index 798797ab..e8caed52 100644 --- a/VNFs/DPPD-PROX/tx_pkt.h +++ b/VNFs/DPPD-PROX/tx_pkt.h @@ -78,5 +78,10 @@ uint16_t tx_try_self(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t tx function. This tx function can be used to make each task a sink. */ int tx_pkt_drop_all(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out); +int tx_pkt_l3(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out); + +void tx_ring_cti(struct task_base *tbase, struct rte_ring *ring, uint16_t command, struct rte_mbuf *mbuf, uint8_t core_id, uint8_t task_id, uint32_t ip); +void tx_ring_ip(struct task_base *tbase, struct rte_ring *ring, uint16_t command, struct rte_mbuf *mbuf, uint32_t ip); +void tx_ring(struct task_base *tbase, struct rte_ring *ring, uint16_t command, struct rte_mbuf *mbuf); #endif /* _TX_PKT_H_ */ diff --git a/VNFs/DPPD-PROX/version.h b/VNFs/DPPD-PROX/version.h index b906b14b..a1d01235 100644 --- a/VNFs/DPPD-PROX/version.h +++ b/VNFs/DPPD-PROX/version.h @@ -22,7 +22,7 @@ /* PROGRAM_NAME defined through Makefile */ #define VERSION_MAJOR 0 -#define VERSION_MINOR 39 +#define VERSION_MINOR 41 #define VERSION_REV 0 #if VERSION_REV > 0 -- 2.16.6