/**
 * A callback for timeouts.
 *
 * Called on forwarding lcores only.
 */
void
dpdk_fragment_assembler_table_scan(void *arg)
{
    unsigned int i, j, scanned = 0;
    unsigned int cpu;
    struct fragment_bucket *vfb;

    cpu = vr_get_cpu() - VR_DPDK_FWD_LCORE_ID;
    assert(cpu >= 0 && cpu < (vr_num_cpus - VR_DPDK_FWD_LCORE_ID));

    i = assembler_scan_index;
    for (j = 0; j < VR_LINUX_ASSEMBLER_BUCKETS; j++) {
        vfb = &assembler_table[cpu][(i + j) % VR_LINUX_ASSEMBLER_BUCKETS];

        if (vfb->frag_list)
            scanned += vr_assembler_table_scan(&vfb->frag_list);

        if (scanned > assembler_scan_thresh) {
            j++;
            break;
        }
    }

    assembler_scan_index = (i + j) % VR_LINUX_ASSEMBLER_BUCKETS;
    return;
}
static void
vr_linux_assembler_table_scan(void *arg)
{
    unsigned int i, j, scanned = 0;

    struct vr_linux_fragment_bucket *vfb;

    i = vr_linux_assembler_scan_index;
    for (j = 0; j < VR_ASSEMBLER_BUCKET_COUNT; j++) {
        vfb = &vr_linux_assembler_table[(i + j) % VR_ASSEMBLER_BUCKET_COUNT];
        spin_lock_bh(&vfb->vfb_lock);
        if (vfb->vfb_frag_list)
            scanned += vr_assembler_table_scan(&vfb->vfb_frag_list);
        spin_unlock_bh(&vfb->vfb_lock);
        if (scanned > vr_linux_assembler_scan_thresh) {
            j++;
            break;
        }
    }

    vr_linux_assembler_scan_index = (i + j) % VR_ASSEMBLER_BUCKET_COUNT;
    return;
}