+static int task_gen_allocate_templates(struct task_gen *task, uint32_t orig_nb_pkts, uint32_t nb_pkts, int do_panic, int pcap)
+{
+ size_t mem_size = nb_pkts * sizeof(*task->pkt_template);
+ size_t orig_mem_size = orig_nb_pkts * sizeof(*task->pkt_template);
+ task->pkt_template = prox_zmalloc(mem_size, task->socket_id);
+ task->pkt_template_orig = prox_zmalloc(orig_mem_size, task->socket_id);
+
+ if (task->pkt_template == NULL || task->pkt_template_orig == NULL) {
+ plog_err_or_panic(do_panic, "Failed to allocate %lu bytes (in huge pages) for %s\n", mem_size, pcap ? "pcap file":"packet template");
+ return -1;
+ }
+
+ for (size_t i = 0; i < orig_nb_pkts; i++) {
+ task->pkt_template_orig[i].buf = prox_zmalloc(task->max_frame_size, task->socket_id);
+ if (task->pkt_template_orig[i].buf == NULL) {
+ plog_err_or_panic(do_panic, "Failed to allocate %u bytes (in huge pages) for %s\n", task->max_frame_size, pcap ? "packet from pcap": "packet");
+ return -1;
+ }
+ }
+ for (size_t i = 0; i < nb_pkts; i++) {
+ task->pkt_template[i].buf = prox_zmalloc(task->max_frame_size, task->socket_id);
+ if (task->pkt_template[i].buf == NULL) {
+ plog_err_or_panic(do_panic, "Failed to allocate %u bytes (in huge pages) for %s\n", task->max_frame_size, pcap ? "packet from pcap": "packet");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int task_gen_reallocate_templates(struct task_gen *task, uint32_t nb_pkts, int do_panic)
+{
+ // Need to free up bufs allocated in previous (longer) imix
+ for (size_t i = nb_pkts; i < task->n_pkts; i++) {
+ if (task->pkt_template[i].buf) {
+ rte_free(task->pkt_template[i].buf);
+ task->pkt_template[i].buf = NULL;
+ }
+ }
+
+ size_t mem_size = nb_pkts * sizeof(*task->pkt_template);
+ size_t old_mem_size = task->n_pkts * sizeof(*task->pkt_template);
+ if (old_mem_size > mem_size)
+ old_mem_size = mem_size;
+
+ struct pkt_template *ptr;
+
+ // re-allocate memory for new pkt_template (this might allocate additional memory or free up some...)
+ if ((ptr = rte_malloc_socket(NULL, mem_size, RTE_CACHE_LINE_SIZE, task->socket_id)) != NULL) {
+ memcpy(ptr, task->pkt_template, old_mem_size);
+ rte_free(task->pkt_template);
+ task->pkt_template = ptr;
+ } else {
+ plog_err_or_panic(do_panic, "Failed to allocate %lu bytes (in huge pages) for packet template for IMIX\n", mem_size);
+ return -1;
+ }
+
+ // Need to allocate bufs for new template but no need to reallocate for existing ones
+ for (size_t i = task->n_pkts; i < nb_pkts; ++i) {
+ task->pkt_template[i].buf = prox_zmalloc(task->max_frame_size, task->socket_id);
+ if (task->pkt_template[i].buf == NULL) {
+ plog_err_or_panic(do_panic, "Failed to allocate %u bytes (in huge pages) for packet %zd in IMIX\n", task->max_frame_size, i);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int check_pkt_size(struct task_gen *task, uint32_t pkt_size, int do_panic)
+{
+ const uint16_t min_len = sizeof(prox_rte_ether_hdr) + sizeof(prox_rte_ipv4_hdr);
+ const uint16_t max_len = task->max_frame_size;
+
+ if (do_panic) {
+ PROX_PANIC(pkt_size == 0, "Invalid packet size length (no packet defined?)\n");
+ PROX_PANIC(pkt_size > max_len, "pkt_size out of range (must be <= %u)\n", max_len);
+ PROX_PANIC(pkt_size < min_len, "pkt_size out of range (must be >= %u)\n", min_len);
+ return 0;
+ } else {
+ if (pkt_size == 0) {
+ plog_err("Invalid packet size length (no packet defined?)\n");
+ return -1;
+ }
+ if (pkt_size > max_len) {
+ if (pkt_size > PROX_RTE_ETHER_MAX_LEN + 2 * PROX_VLAN_TAG_SIZE - 4)
+ plog_err("pkt_size too high and jumbo frames disabled\n");
+ else
+ plog_err("pkt_size out of range (must be <= (mtu=%u))\n", max_len);
+ return -1;
+ }
+ if (pkt_size < min_len) {
+ plog_err("pkt_size out of range (must be >= %u)\n", min_len);
+ return -1;
+ }
+ return 0;
+ }
+}
+
+static int check_fields_in_bounds(struct task_gen *task, uint32_t pkt_size, int do_panic)
+{
+ if (task->lat_enabled) {
+ uint32_t pos_beg = task->lat_pos;
+ uint32_t pos_end = task->lat_pos + 3U;
+
+ if (do_panic)
+ PROX_PANIC(pkt_size <= pos_end, "Writing latency at %u-%u, but packet size is %u bytes\n",
+ pos_beg, pos_end, pkt_size);
+ else if (pkt_size <= pos_end) {
+ plog_err("Writing latency at %u-%u, but packet size is %u bytes\n", pos_beg, pos_end, pkt_size);
+ return -1;
+ }
+ }
+ if (task->packet_id_pos) {
+ uint32_t pos_beg = task->packet_id_pos;
+ uint32_t pos_end = task->packet_id_pos + 4U;
+
+ if (do_panic)
+ PROX_PANIC(pkt_size <= pos_end, "Writing packet at %u-%u, but packet size is %u bytes\n",
+ pos_beg, pos_end, pkt_size);
+ else if (pkt_size <= pos_end) {
+ plog_err("Writing packet at %u-%u, but packet size is %u bytes\n", pos_beg, pos_end, pkt_size);
+ return -1;
+ }
+ }
+ if (task->accur_pos) {
+ uint32_t pos_beg = task->accur_pos;
+ uint32_t pos_end = task->accur_pos + 3U;
+
+ if (do_panic)
+ PROX_PANIC(pkt_size <= pos_end, "Writing accuracy at %u-%u, but packet size is %u bytes\n",
+ pos_beg, pos_end, pkt_size);
+ else if (pkt_size <= pos_end) {
+ plog_err("Writing accuracy at %u-%u, but packet size is %u bytes\n", pos_beg, pos_end, pkt_size);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int task_gen_set_eth_ip_udp_sizes(struct task_gen *task, uint32_t n_orig_pkts, uint32_t nb_pkt_sizes, uint32_t *pkt_sizes)
+{
+ size_t k;
+ uint32_t l4_len;
+ prox_rte_ipv4_hdr *ip;
+ struct pkt_template *template;
+
+ for (size_t j = 0; j < nb_pkt_sizes; ++j) {
+ for (size_t i = 0; i < n_orig_pkts; ++i) {
+ k = j * n_orig_pkts + i;
+ template = &task->pkt_template[k];
+ if (template->l2_len == 0)
+ continue;
+ ip = (prox_rte_ipv4_hdr *)(template->buf + template->l2_len);
+ ip->total_length = rte_bswap16(pkt_sizes[j] - template->l2_len);
+ l4_len = pkt_sizes[j] - template->l2_len - template->l3_len;
+ ip->hdr_checksum = 0;
+ prox_ip_cksum_sw(ip);
+
+ if (ip->next_proto_id == IPPROTO_UDP) {
+ prox_rte_udp_hdr *udp = (prox_rte_udp_hdr *)(((uint8_t *)ip) + template->l3_len);
+ udp->dgram_len = rte_bswap16(l4_len);
+ prox_udp_cksum_sw(udp, l4_len, ip->src_addr, ip->dst_addr);
+ } else if (ip->next_proto_id == IPPROTO_TCP) {
+ prox_rte_tcp_hdr *tcp = (prox_rte_tcp_hdr *)(((uint8_t *)ip) + template->l3_len);
+ prox_tcp_cksum_sw(tcp, l4_len, ip->src_addr, ip->dst_addr);
+ }
+ }
+ }
+ return 0;
+}
+
+static int task_gen_apply_imix(struct task_gen *task, int do_panic)
+{
+ struct pkt_template *ptr;
+ int rc;
+ task->imix_nb_pkts = task->new_imix_nb_pkts;
+ uint32_t n_pkts = task->imix_nb_pkts * task->orig_n_pkts;
+
+ if ((n_pkts != task->n_pkts) && ((rc = task_gen_reallocate_templates(task, n_pkts, do_panic)) < 0))
+ return rc;
+
+ task->n_pkts = n_pkts;
+ if (task->pkt_idx >= n_pkts)
+ task->pkt_idx = 0;
+ task_gen_set_pkt_templates_len(task, task->imix_pkt_sizes);
+ task_gen_reset_pkt_templates_content(task);
+ task_gen_pkt_template_recalc_metadata(task);
+ check_all_pkt_size(task, DO_NOT_PANIC);
+ check_all_fields_in_bounds(task, DO_NOT_PANIC);
+ task_gen_set_eth_ip_udp_sizes(task, task->orig_n_pkts, task->imix_nb_pkts, task->imix_pkt_sizes);
+ return 0;
+}
+