// See the License for the specific language governing permissions and
// limitations under the License.
*/
-
#include <rte_mbuf.h>
#include <pcap.h>
#include <string.h>
uint8_t *buf;
};
-#define MAX_TEMPLATE_INDEX 65536
-#define TEMPLATE_INDEX_MASK (MAX_TEMPLATE_INDEX - 1)
-
#define IP4(x) x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, x >> 24
+#define TASK_OVERWRITE_SRC_MAC_WITH_PORT_MAC 1
+
static void pkt_template_init_mbuf(struct pkt_template *pkt_template, struct rte_mbuf *mbuf, uint8_t *pkt)
{
const uint32_t pkt_size = pkt_template->len;
uint16_t rand_offset; /* each random has an offset*/
uint8_t rand_len; /* # bytes to take from random (no bias introduced) */
} rand[64];
- uint64_t accur[64];
+ uint64_t accur[ACCURACY_WINDOW];
uint64_t pkt_tsc_offset[64];
struct pkt_template *pkt_template_orig; /* packet templates (from inline or from pcap) */
struct ether_addr src_mac;
*(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)
if (!task->accur_pos)
return;
- /* The accuracy of task->pkt_queue_index - 64 is stored in
- packet task->pkt_queue_index. The ID modulo 64 is the
+ /* The accuracy of task->pkt_queue_index - ACCURACY_WINDOW is stored in
+ packet task->pkt_queue_index. The ID modulo ACCURACY_WINDOW is the
same. */
for (uint16_t j = 0; j < count; ++j) {
- uint32_t accuracy = task->accur[(task->pkt_queue_index + j) & 63];
+ uint32_t accuracy = task->accur[(task->pkt_queue_index + j) & (ACCURACY_WINDOW - 1)];
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) {
- task_gen_apply_sig(task, pkt_hdr[j]);
- }
-}
-
static void task_gen_apply_unique_id(struct task_gen *task, uint8_t *pkt_hdr, const struct unique_id *id)
{
struct unique_id *dst = (struct unique_id *)(pkt_hdr + task->packet_id_pos);
uint64_t first_accuracy_idx = task->pkt_queue_index - count;
for (uint32_t i = 0; i < count; ++i) {
- uint32_t accuracy_idx = (first_accuracy_idx + i) & 63;
+ uint32_t accuracy_idx = (first_accuracy_idx + i) & (ACCURACY_WINDOW - 1);
task->accur[accuracy_idx] = accur;
}
struct pkt_template *pktpl = &task->pkt_template[task->pkt_idx];
struct pkt_template *pkt_template = &task->pkt_template[task->pkt_idx];
pkt_template_init_mbuf(pkt_template, mbufs[i], pkt_hdr[i]);
- 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_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;
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;
}
return (tot_inter_pkt + n / 2)/n;
}
-static int pcap_read_pkts(pcap_t *handle, const char *file_name, uint32_t n_pkts, struct pkt_template *proto, uint64_t *time_stamp)
+static int pcap_read_pkts(pcap_t *handle, const char *file_name, uint32_t n_pkts, struct pkt_template *proto, uint64_t *time_stamp, uint32_t max_frame_size)
{
struct pcap_pkthdr header;
const uint8_t *buf;
PROX_PANIC(buf == NULL, "Failed to read packet %d from pcap %s\n", i, file_name);
proto[i].len = header.len;
- len = RTE_MIN(header.len, sizeof(proto[i].buf));
+ len = RTE_MIN(header.len, max_frame_size);
if (header.len > len)
plogx_warn("Packet truncated from %u to %zu bytes\n", header.len, len);
for (size_t i = 0; i < task->n_pkts; ++i) {
src = &task->pkt_template_orig[i];
dst = &task->pkt_template[i];
- memcpy(dst->buf, src->buf, dst->len);
+ memcpy(dst->buf, src->buf, RTE_MAX(src->len, dst->len));
+ task_gen_apply_sig(task, dst);
}
}
PROX_PANIC(handle == NULL, "Failed to open PCAP file: %s\n", err);
task->n_pkts = pcap_count_pkts(handle, &max_frame_size);
- plogx_info("%u packets in pcap file '%s'\n", task->n_pkts, targ->pcap_file);
+ plogx_info("%u packets in pcap file '%s'; max frame size=%d\n", task->n_pkts, targ->pcap_file, max_frame_size);
PROX_PANIC(max_frame_size > task->max_frame_size,
max_frame_size > ETHER_MAX_LEN + 2 * PROX_VLAN_TAG_SIZE -4 ?
"pkt_size too high and jumbo frames disabled" : "pkt_size > mtu");
if (targ->n_pkts)
task->n_pkts = RTE_MIN(task->n_pkts, targ->n_pkts);
- PROX_PANIC(task->n_pkts > MAX_TEMPLATE_INDEX, "Too many packets specified in pcap - increase MAX_TEMPLATE_INDEX\n");
plogx_info("Loading %u packets from pcap\n", task->n_pkts);
size_t mem_size = task->n_pkts * sizeof(*task->pkt_template);
task->pkt_template = prox_zmalloc(mem_size, socket_id);
"Failed to allocate %lu bytes (in huge pages) for pcap file\n", mem_size);
for (uint i = 0; i < task->n_pkts; i++) {
- task->pkt_template[i].buf = prox_zmalloc(max_frame_size, socket_id);
- task->pkt_template_orig[i].buf = prox_zmalloc(max_frame_size, socket_id);
+ task->pkt_template[i].buf = prox_zmalloc(task->max_frame_size, socket_id);
+ task->pkt_template_orig[i].buf = prox_zmalloc(task->max_frame_size, socket_id);
PROX_PANIC(task->pkt_template->buf == NULL ||
task->pkt_template_orig->buf == NULL,
"Failed to allocate %u bytes (in huge pages) for pcap file\n", task->max_frame_size);
}
- pcap_read_pkts(handle, targ->pcap_file, task->n_pkts, task->pkt_template_orig, NULL);
+ pcap_read_pkts(handle, targ->pcap_file, task->n_pkts, task->pkt_template_orig, NULL, max_frame_size);
pcap_close(handle);
task_gen_reset_pkt_templates(task);
}
struct task_gen *task = (struct task_gen *)tbase;
int rc;
- if ((rc = check_pkt_size(task, pkt_size, 0)) != 0)
- return rc;
- if ((rc = check_fields_in_bounds(task, pkt_size, 0)) != 0)
- return rc;
- task->pkt_template[0].len = pkt_size;
- return rc;
+ for (size_t i = 0; i < task->n_pkts; ++i) {
+ if ((rc = check_pkt_size(task, pkt_size, 0)) != 0)
+ return rc;
+ if ((rc = check_fields_in_bounds(task, pkt_size, 0)) != 0)
+ return rc;
+ }
+ for (size_t i = 0; i < task->n_pkts; ++i) {
+ task->pkt_template[i].len = pkt_size;
+ }
+ return 0;
}
void task_gen_set_rate(struct task_base *tbase, uint64_t bps)
{
struct task_gen *task = (struct task_gen *)tbase;
+ if (offset + len > task->max_frame_size)
+ return -1;
for (size_t i = 0; i < task->n_pkts; ++i) {
uint32_t to_write = rte_cpu_to_be_32(value) >> ((4 - len) * 8);
uint8_t *dst = task->pkt_template[i].buf;
struct task_gen *task = (struct task_gen *)tbase;
task_gen_reset_pkt_templates_content(task);
+ if (task->flags & TASK_OVERWRITE_SRC_MAC_WITH_PORT_MAC) {
+ for (uint32_t i = 0; i < task->n_pkts; ++i) {
+ rte_memcpy(&task->pkt_template[i].buf[sizeof(struct ether_addr)], &task->src_mac, sizeof(struct ether_addr));
+ }
+ }
}
uint32_t task_gen_get_n_randoms(struct task_base *tbase)
if (task->n_pkts > targ->n_pkts)
task->n_pkts = targ->n_pkts;
}
- PROX_PANIC(task->n_pkts > MAX_TEMPLATE_INDEX, "Too many packets specified in pcap - increase MAX_TEMPLATE_INDEX\n");
-
plogx_info("Loading %u packets from pcap\n", task->n_pkts);
size_t mem_size = task->n_pkts * (sizeof(*task->proto) + sizeof(*task->proto_tsc));
PROX_PANIC(task->proto[i].buf == NULL, "Failed to allocate %u bytes (in huge pages) for pcap file\n", max_frame_size);
}
- pcap_read_pkts(handle, targ->pcap_file, task->n_pkts, task->proto, task->proto_tsc);
+ pcap_read_pkts(handle, targ->pcap_file, task->n_pkts, task->proto, task->proto_tsc, max_frame_size);
pcap_close(handle);
}
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) / bytes_per_hz;
+ task->bytes_to_tsc[i] = (task->hz * i * 0.99) / bytes_per_hz;
}
if (!strcmp(targ->pcap_file, "")) {
PROX_PANIC(((targ->nb_txrings == 0) && (targ->nb_txports == 0)), "Gen mode requires a tx ring or a tx port");
if ((targ->flags & DSF_KEEP_SRC_MAC) == 0) {
- uint8_t *src_addr = prox_port_cfg[tbase->tx_params_hw.tx_port_queue->port].eth_addr.addr_bytes;
+ task->flags |= TASK_OVERWRITE_SRC_MAC_WITH_PORT_MAC;
+ memcpy(&task->src_mac, &prox_port_cfg[task->base.tx_params_hw.tx_port_queue->port].eth_addr, sizeof(struct ether_addr));
for (uint32_t i = 0; i < task->n_pkts; ++i) {
- rte_memcpy(&task->pkt_template[i].buf[6], src_addr, 6);
+ rte_memcpy(&task->pkt_template[i].buf[sizeof(struct ether_addr)], &task->src_mac, sizeof(struct ether_addr));
}
}
- memcpy(&task->src_mac, &prox_port_cfg[task->base.tx_params_hw.tx_port_queue->port].eth_addr, sizeof(struct ether_addr));
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");
.size = sizeof(struct task_gen)
};
+/* This mode uses time stamps in the pcap file */
static struct task_init task_init_gen_pcap = {
.mode_str = "gen",
.sub_mode_str = "pcap",