* Virtual Ethernet interfaces.
  *
  * For each mode, the following tests are run:
- *    a. nopoll - soft-irq processing
+ *    a. nopoll - soft-irq processing in run-to-completion mode
  *    b. poll - using poll() syscall
  *    c. Socket Teardown
  *       Create a Tx and a Rx socket, Tx from one socket, Rx on another. Destroy
  *       Configure sockets at indexes 0 and 1, run a traffic on queue ids 0,
  *       then remove xsk sockets from queue 0 on both veth interfaces and
  *       finally run a traffic on queues ids 1
+ *    g. unaligned mode
  *
  * Total tests: 12
  *
        };
        int ret;
 
+       if (umem->unaligned_mode)
+               cfg.flags |= XDP_UMEM_UNALIGNED_CHUNK_FLAG;
+
        ret = xsk_umem__create(&umem->umem, buffer, size,
                               &umem->fq, &umem->cq, &cfg);
        if (ret)
        return 0;
 }
 
-static void xsk_populate_fill_ring(struct xsk_umem_info *umem)
-{
-       int ret, i;
-       u32 idx = 0;
-
-       ret = xsk_ring_prod__reserve(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
-       if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
-               exit_with_error(-ret);
-       for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
-               *xsk_ring_prod__fill_addr(&umem->fq, idx++) = i * umem->frame_size;
-       xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
-}
-
 static int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,
                                struct ifobject *ifobject, u32 qid)
 {
        struct pkt_stream *pkt_stream;
        u32 i;
 
-       pkt_stream = malloc(sizeof(*pkt_stream));
+       pkt_stream = calloc(1, sizeof(*pkt_stream));
        if (!pkt_stream)
                exit_with_error(ENOMEM);
 
 
        pkt_stream->nb_pkts = nb_pkts;
        for (i = 0; i < nb_pkts; i++) {
-               pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size;
+               pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size +
+                       DEFAULT_OFFSET;
                pkt_stream->pkts[i].len = pkt_len;
                pkt_stream->pkts[i].payload = i;
 
        return pkt_stream;
 }
 
+static struct pkt_stream *pkt_stream_clone(struct xsk_umem_info *umem,
+                                          struct pkt_stream *pkt_stream)
+{
+       return pkt_stream_generate(umem, pkt_stream->nb_pkts, pkt_stream->pkts[0].len);
+}
+
 static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len)
 {
        struct pkt_stream *pkt_stream;
        test->ifobj_rx->pkt_stream = pkt_stream;
 }
 
+static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, u32 offset)
+{
+       struct xsk_umem_info *umem = test->ifobj_tx->umem;
+       struct pkt_stream *pkt_stream;
+       u32 i;
+
+       pkt_stream = pkt_stream_clone(umem, test->pkt_stream_default);
+       for (i = 0; i < test->pkt_stream_default->nb_pkts; i += 2) {
+               pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size + offset;
+               pkt_stream->pkts[i].len = pkt_len;
+       }
+
+       test->ifobj_tx->pkt_stream = pkt_stream;
+       test->ifobj_rx->pkt_stream = pkt_stream;
+}
+
 static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb)
 {
        struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb);
        fprintf(stdout, "---------------------------------------\n");
 }
 
-static bool is_pkt_valid(struct pkt *pkt, void *buffer, const struct xdp_desc *desc)
+static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len)
 {
-       void *data = xsk_umem__get_data(buffer, desc->addr);
+       void *data = xsk_umem__get_data(buffer, addr);
        struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr));
 
        if (!pkt) {
                if (opt_pkt_dump)
                        pkt_dump(data, PKT_SIZE);
 
-               if (pkt->len != desc->len) {
+               if (pkt->len != len) {
                        ksft_test_result_fail
                                ("ERROR: [%s] expected length [%d], got length [%d]\n",
-                                       __func__, pkt->len, desc->len);
+                                       __func__, pkt->len, len);
                        return false;
                }
 
 
                        orig = xsk_umem__extract_addr(addr);
                        addr = xsk_umem__add_offset_to_addr(addr);
-                       if (!is_pkt_valid(pkt, xsk->umem->buffer, desc))
+                       if (!is_pkt_valid(pkt, xsk->umem->buffer, addr, desc->len))
                                return;
 
                        *xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = orig;
 
 static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject)
 {
+       int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
        u32 i;
 
        ifobject->ns_fd = switch_namespace(ifobject->nsname);
 
+       if (ifobject->umem->unaligned_mode)
+               mmap_flags |= MAP_HUGETLB;
+
        for (i = 0; i < test->nb_sockets; i++) {
                u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
-               int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
                u32 ctr = 0;
                void *bufs;
 
        pthread_exit(NULL);
 }
 
+static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream)
+{
+       u32 idx = 0, i;
+       int ret;
+
+       ret = xsk_ring_prod__reserve(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
+       if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
+               exit_with_error(ENOSPC);
+       for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++) {
+               u64 addr;
+
+               if (pkt_stream->use_addr_for_fill) {
+                       struct pkt *pkt = pkt_stream_get_pkt(pkt_stream, i);
+
+                       if (!pkt)
+                               break;
+                       addr = pkt->addr;
+               } else {
+                       addr = (i % umem->num_frames) * umem->frame_size + DEFAULT_OFFSET;
+               }
+
+               *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr;
+       }
+       xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
+}
+
 static void *worker_testapp_validate_rx(void *arg)
 {
        struct test_spec *test = (struct test_spec *)arg;
                thread_common_ops(test, ifobject);
 
        if (stat_test_type != STAT_TEST_RX_FILL_EMPTY)
-               xsk_populate_fill_ring(ifobject->umem);
+               xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream);
 
        fds.fd = xsk_socket__fd(ifobject->xsk->xsk);
        fds.events = POLLIN;
        test_spec_set_name(test, "STATS");
 }
 
+/* Simple test */
+static bool hugepages_present(struct ifobject *ifobject)
+{
+       const size_t mmap_sz = 2 * ifobject->umem->num_frames * ifobject->umem->frame_size;
+       void *bufs;
+
+       bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_HUGETLB, -1, 0);
+       if (bufs == MAP_FAILED)
+               return false;
+
+       munmap(bufs, mmap_sz);
+       return true;
+}
+
+static bool testapp_unaligned(struct test_spec *test)
+{
+       if (!hugepages_present(test->ifobj_tx)) {
+               ksft_test_result_skip("No 2M huge pages present.\n");
+               return false;
+       }
+
+       test_spec_set_name(test, "UNALIGNED_MODE");
+       test->ifobj_tx->umem->unaligned_mode = true;
+       test->ifobj_rx->umem->unaligned_mode = true;
+       /* Let half of the packets straddle a buffer boundrary */
+       pkt_stream_replace_half(test, PKT_SIZE, test->ifobj_tx->umem->frame_size - 32);
+       test->ifobj_rx->pkt_stream->use_addr_for_fill = true;
+       testapp_validate_traffic(test);
+
+       pkt_stream_restore_default(test);
+       return true;
+}
+
 static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac,
                       const char *dst_ip, const char *src_ip, const u16 dst_port,
                       const u16 src_port, thread_func_t func_ptr)
                test_spec_set_name(test, "POLL");
                testapp_validate_traffic(test);
                break;
+       case TEST_TYPE_UNALIGNED:
+               if (!testapp_unaligned(test))
+                       return;
+               break;
        default:
                break;
        }