X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=VNFs%2FDPPD-PROX%2Fhandle_gen.c;h=4bf2e6eb8426f2823f7bd77103c8dc7fe62a2fda;hb=0d8616af8418480595a2c53e1dc7c3b809962a28;hp=4040b334e5a379a26abc09452fe11bc9ee22d5db;hpb=d338068b8f832e23b54bf72cf4994410e88c8f60;p=samplevnf.git diff --git a/VNFs/DPPD-PROX/handle_gen.c b/VNFs/DPPD-PROX/handle_gen.c index 4040b334..4bf2e6eb 100644 --- a/VNFs/DPPD-PROX/handle_gen.c +++ b/VNFs/DPPD-PROX/handle_gen.c @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. */ - #include #include #include @@ -57,7 +56,6 @@ struct pkt_template { #define MAX_TEMPLATE_INDEX 65536 #define TEMPLATE_INDEX_MASK (MAX_TEMPLATE_INDEX - 1) -#define MBUF_ARP MAX_TEMPLATE_INDEX #define IP4(x) x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, x >> 24 @@ -86,7 +84,6 @@ struct task_gen_pcap { struct task_gen { struct task_base base; uint64_t hz; - uint64_t link_speed; struct token_time token_time; struct local_mbuf local_mbuf; struct pkt_template *pkt_template; /* packet templates used at runtime */ @@ -124,6 +121,7 @@ struct task_gen { uint8_t flags; uint8_t cksum_offload; struct prox_port_cfg *port; + uint64_t *bytes_to_tsc; } __rte_cache_aligned; static inline uint8_t ipv4_get_hdr_len(struct ipv4_hdr *ip) @@ -262,15 +260,9 @@ static int handle_gen_pcap_bulk(struct task_base *tbase, struct rte_mbuf **mbuf, return task->base.tx_pkt(&task->base, new_pkts, send_bulk, NULL); } -static uint64_t bytes_to_tsc(struct task_gen *task, uint32_t bytes) +static inline uint64_t bytes_to_tsc(struct task_gen *task, uint32_t bytes) { - const uint64_t hz = task->hz; - const uint64_t bytes_per_hz = task->link_speed; - - if (bytes_per_hz == UINT64_MAX) - return 0; - - return hz * bytes / bytes_per_hz; + return task->bytes_to_tsc[bytes]; } static uint32_t task_gen_next_pkt_idx(const struct task_gen *task, uint32_t pkt_idx) @@ -360,9 +352,10 @@ static void task_gen_apply_accur_pos(struct task_gen *task, uint8_t *pkt_hdr, ui *(uint32_t *)(pkt_hdr + task->accur_pos) = accuracy; } -static void task_gen_apply_sig(struct task_gen *task, uint8_t *pkt_hdr) +static void task_gen_apply_sig(struct task_gen *task, struct pkt_template *dst) { - *(uint32_t *)(pkt_hdr + task->sig_pos) = task->sig; + if (task->sig_pos) + *(uint32_t *)(dst->buf + task->sig_pos) = task->sig; } static void task_gen_apply_all_accur_pos(struct task_gen *task, struct rte_mbuf **mbufs, uint8_t **pkt_hdr, uint32_t count) @@ -374,22 +367,8 @@ static void task_gen_apply_all_accur_pos(struct task_gen *task, struct rte_mbuf packet task->pkt_queue_index. The ID modulo 64 is the same. */ for (uint16_t j = 0; j < count; ++j) { - if ((mbufs[j]->udata64 & MBUF_ARP) == 0) { - uint32_t accuracy = task->accur[(task->pkt_queue_index + j) & 63]; - task_gen_apply_accur_pos(task, pkt_hdr[j], accuracy); - } - } -} - -static void task_gen_apply_all_sig(struct task_gen *task, struct rte_mbuf **mbufs, uint8_t **pkt_hdr, uint32_t count) -{ - if (!task->sig_pos) - return; - - for (uint16_t j = 0; j < count; ++j) { - if ((mbufs[j]->udata64 & MBUF_ARP) == 0) { - task_gen_apply_sig(task, pkt_hdr[j]); - } + uint32_t accuracy = task->accur[(task->pkt_queue_index + j) & 63]; + task_gen_apply_accur_pos(task, pkt_hdr[j], accuracy); } } @@ -406,11 +385,9 @@ static void task_gen_apply_all_unique_id(struct task_gen *task, struct rte_mbuf return; for (uint16_t i = 0; i < count; ++i) { - if ((mbufs[i]->udata64 & MBUF_ARP) == 0) { - struct unique_id id; - unique_id_init(&id, task->generator_id, task->pkt_queue_index++); - task_gen_apply_unique_id(task, pkt_hdr[i], &id); - } + struct unique_id id; + unique_id_init(&id, task->generator_id, task->pkt_queue_index++); + task_gen_apply_unique_id(task, pkt_hdr[i], &id); } } @@ -424,11 +401,9 @@ static void task_gen_checksum_packets(struct task_gen *task, struct rte_mbuf **m uint32_t pkt_idx = task_gen_offset_pkt_idx(task, - count); for (uint16_t i = 0; i < count; ++i) { - if ((mbufs[i]->udata64 & MBUF_ARP) == 0) { - struct pkt_template *pkt_template = &task->pkt_template[pkt_idx]; - checksum_packet(pkt_hdr[i], mbufs[i], pkt_template, task->cksum_offload); - pkt_idx = task_gen_next_pkt_idx(task, pkt_idx); - } + struct pkt_template *pkt_template = &task->pkt_template[pkt_idx]; + checksum_packet(pkt_hdr[i], mbufs[i], pkt_template, task->cksum_offload); + pkt_idx = task_gen_next_pkt_idx(task, pkt_idx); } } @@ -448,8 +423,12 @@ static uint64_t task_gen_calc_bulk_duration(struct task_gen *task, uint32_t coun uint32_t pkt_idx = task_gen_offset_pkt_idx(task, - 1); struct pkt_template *last_pkt_template = &task->pkt_template[pkt_idx]; uint32_t last_pkt_len = pkt_len_to_wire_size(last_pkt_template->len); +#ifdef NO_EXTRAPOLATION + uint64_t bulk_duration = task->pkt_tsc_offset[count - 1]; +#else uint64_t last_pkt_duration = bytes_to_tsc(task, last_pkt_len); uint64_t bulk_duration = task->pkt_tsc_offset[count - 1] + last_pkt_duration; +#endif return bulk_duration; } @@ -484,6 +463,14 @@ static uint64_t task_gen_write_latency(struct task_gen *task, uint8_t **pkt_hdr, simply sleeping until delta_t is zero would leave a period of silence on the line. The error has been introduced earlier, but the packets have already been sent. */ + + /* This happens typically if previous bulk was delayed + by an interrupt e.g. (with Time in nsec) + Time x: sleep 4 microsec + Time x+4000: send 64 packets (64 packets as 4000 nsec, w/ 10Gbps 64 bytes) + Time x+5000: send 16 packets (16 packets as 1000 nsec) + When we send the 16 packets, the 64 ealier packets are not yet + fully sent */ if (tx_tsc < task->earliest_tsc_next_pkt) delta_t = task->earliest_tsc_next_pkt - tx_tsc; else @@ -492,12 +479,10 @@ static uint64_t task_gen_write_latency(struct task_gen *task, uint8_t **pkt_hdr, for (uint16_t i = 0; i < count; ++i) { uint32_t *pos = (uint32_t *)(pkt_hdr[i] + task->lat_pos); const uint64_t pkt_tsc = tx_tsc + delta_t + task->pkt_tsc_offset[i]; - *pos = pkt_tsc >> LATENCY_ACCURACY; } uint64_t bulk_duration = task_gen_calc_bulk_duration(task, count); - task->earliest_tsc_next_pkt = tx_tsc + delta_t + bulk_duration; write_tsc_after = rte_rdtsc(); task->write_duration_estimate = write_tsc_after - write_tsc_before; @@ -507,6 +492,7 @@ static uint64_t task_gen_write_latency(struct task_gen *task, uint8_t **pkt_hdr, do { tsc_before_tx = rte_rdtsc(); } while (tsc_before_tx < tx_tsc); + return tsc_before_tx; } @@ -546,7 +532,11 @@ static void task_gen_build_packets(struct task_gen *task, struct rte_mbuf **mbuf mbufs[i]->udata64 = task->pkt_idx & TEMPLATE_INDEX_MASK; struct ether_hdr *hdr = (struct ether_hdr *)pkt_hdr[i]; if (task->lat_enabled) { +#ifdef NO_EXTRAPOLATION + task->pkt_tsc_offset[i] = 0; +#else task->pkt_tsc_offset[i] = bytes_to_tsc(task, will_send_bytes); +#endif will_send_bytes += pkt_len_to_wire_size(pkt_template->len); } task->pkt_idx = task_gen_next_pkt_idx(task, task->pkt_idx); @@ -642,16 +632,6 @@ static int handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin int i, j; - // If link is down, link_speed is 0 - if (unlikely(task->link_speed == 0)) { - if (task->port && task->port->link_speed != 0) { - task->link_speed = task->port->link_speed * 125000L; - plog_info("\tPort %u: link speed is %ld Mbps\n", - (uint8_t)(task->port - prox_port_cfg), 8 * task->link_speed / 1000000); - } else - return 0; - } - task_gen_update_config(task); if (task->pkt_count == 0) { @@ -680,7 +660,6 @@ static int handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin task_gen_build_packets(task, new_pkts, pkt_hdr, send_bulk); task_gen_apply_all_random_fields(task, pkt_hdr, send_bulk); 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); uint64_t tsc_before_tx; @@ -689,6 +668,20 @@ static int handle_gen_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin task_gen_checksum_packets(task, new_pkts, pkt_hdr, send_bulk); ret = task->base.tx_pkt(&task->base, new_pkts, send_bulk, out); task_gen_store_accuracy(task, send_bulk, tsc_before_tx); + + // If we failed to send some packets, we need to do some clean-up: + + if (unlikely(ret)) { + // We need re-use the packets indexes not being sent + // Hence non-sent packets will not be considered as lost by the receiver when it looks at + // packet ids. This should also increase the percentage of packets used for latency measurements + task->pkt_queue_index -= ret; + + // In case of failures, the estimate about when we can send next packet (earliest_tsc_next_pkt) is wrong + // This would result in under-estimated latency (up to 0 or negative) + uint64_t bulk_duration = task_gen_calc_bulk_duration(task, ret); + task->earliest_tsc_next_pkt -= bulk_duration; + } return ret; } @@ -918,6 +911,7 @@ static void task_gen_reset_pkt_templates_content(struct task_gen *task) src = &task->pkt_template_orig[i]; dst = &task->pkt_template[i]; memcpy(dst->buf, src->buf, dst->len); + task_gen_apply_sig(task, dst); } } @@ -1194,18 +1188,7 @@ static void start(struct task_base *tbase) if (tbase->l3.tmaster) { register_all_ip_to_ctrl_plane(task); } - if (task->port) { - // task->port->link_speed reports the link speed in Mbps e.g. 40k for a 40 Gbps NIC. - // task->link_speed reports link speed in Bytes per sec. - // It can be 0 if link is down, and must hence be updated in fast path. - task->link_speed = task->port->link_speed * 125000L; - if (task->link_speed) - plog_info("\tPort %u: link speed is %ld Mbps\n", - (uint8_t)(task->port - prox_port_cfg), 8 * task->link_speed / 1000000); - else - plog_info("\tPort %u: link speed is %ld Mbps - link might be down\n", - (uint8_t)(task->port - prox_port_cfg), 8 * task->link_speed / 1000000); - } + /* 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) @@ -1291,7 +1274,29 @@ static void init_task_gen(struct task_base *tbase, struct task_args *targ) task->generator_id = targ->generator_id; plog_info("\tGenerator id = %d\n", task->generator_id); - task->link_speed = UINT64_MAX; + + // Allocate array holding bytes to tsc for supported frame sizes + task->bytes_to_tsc = prox_zmalloc(task->max_frame_size * MAX_PKT_BURST * sizeof(task->bytes_to_tsc[0]), rte_lcore_to_socket_id(targ->lconf->id)); + PROX_PANIC(task->bytes_to_tsc == NULL, + "Failed to allocate %u bytes (in huge pages) for bytes_to_tsc\n", task->max_frame_size); + + // task->port->max_link_speed reports the maximum, non negotiated ink speed in Mbps e.g. 40k for a 40 Gbps NIC. + // It can be UINT32_MAX (virtual devices or not supported by DPDK < 16.04) + uint64_t bytes_per_hz = UINT64_MAX; + if ((task->port) && (task->port->max_link_speed != UINT32_MAX)) { + bytes_per_hz = task->port->max_link_speed * 125000L; + plog_info("\tPort %u: max link speed is %ld Mbps\n", + (uint8_t)(task->port - prox_port_cfg), 8 * bytes_per_hz / 1000000); + } + // There are cases where hz estimate might be slighly over-estimated + // This results in too much extrapolation + // Only account for 99% of extrapolation to handle cases with up to 1% error clocks + for (unsigned int i = 0; i < task->max_frame_size * MAX_PKT_BURST ; i++) { + if (bytes_per_hz == UINT64_MAX) + task->bytes_to_tsc[i] = 0; + else + task->bytes_to_tsc[i] = (task->hz * i * 0.99) / bytes_per_hz; + } if (!strcmp(targ->pcap_file, "")) { plog_info("\tUsing inline definition of a packet\n");