/**
 * Enqueue a packet to the assembler.
 *
 * Executed only from the forwarding lcores.
 */
int
dpdk_fragment_assembler_enqueue(struct vrouter *router, struct vr_packet *pkt,
                                struct vr_forwarding_md *fmd)
{
    int ret;
    unsigned int cpu;
    struct vr_dpdk_lcore *lcore;

    cpu = vr_get_cpu();
    if (cpu >= vr_num_cpus || cpu < VR_DPDK_FWD_LCORE_ID) {
        RTE_LOG(ERR, VROUTER, "%s:%d Enqueue to the assembler can only be "
                "done on forwarding lcores, not on cpu %u\n",
                __FUNCTION__, __LINE__, cpu);
        vr_pfree(pkt, VP_DROP_FRAGMENTS);
        return -EINVAL;
    }

    ret = vr_fragment_enqueue(router,
                              &per_cpu_queues[cpu - VR_DPDK_FWD_LCORE_ID].queue, pkt, fmd);

    if (!ret) {
        lcore = vr_dpdk.lcores[cpu];
        vr_dpdk_lcore_schedule_assembler_work(lcore, dpdk_fragment_assembler,
                                              &per_cpu_queues[cpu - VR_DPDK_FWD_LCORE_ID].queue);
    }

    return 0;
}
int
lh_enqueue_to_assembler(struct vrouter *router, struct vr_packet *pkt,
        struct vr_forwarding_md *fmd)
{
    int ret;
    unsigned int cpu;

    cpu = vr_get_cpu();
    if (cpu >= vr_num_cpus) {
        printk("cpu is %u, but max cpu is only %u\n", cpu, vr_num_cpus);
        vr_pfree(pkt, VP_DROP_FRAGMENTS);
        return -EINVAL;
    }

    ret = vr_fragment_enqueue(router, &vr_lfq_pcpu_queues[cpu].vrlfq_queue,
            pkt, fmd);
    if (!ret)
        queue_work(vr_linux_assembler_wq, &vr_lfq_pcpu_queues[cpu].vrlfq_work);

    return 0;
}