Esempio n. 1
0
static int
bridge_table_lock(struct vr_interface *vif, uint8_t *mac)
{
    uint8_t lock = 1;
    uint32_t hash;
    unsigned long t1s, t1ns, t2s, t2ns, diff;

    if (!vif->vif_bridge_table_lock)
        return -EINVAL;

    hash = vr_hash(mac, VR_ETHER_ALEN, 0);
    hash %= vr_num_cpus;

    vr_get_mono_time(&t1s, &t1ns);
    while (lock) {
        lock = __sync_lock_test_and_set(&vif->vif_bridge_table_lock[hash],
                lock);
        if (lock) {
            vr_get_mono_time(&t2s, &t2ns);
            if (t2ns >= t1ns) {
                diff = t2ns - t1ns;
            } else {
                diff = 999999999 - t1ns + t2ns;
            }

            if (diff >= 50000) {
                return -EINVAL;
            }
        }
    }

    return hash;
}
Esempio n. 2
0
unsigned int
vr_assembler_table_scan(struct vr_fragment **head)
{
    unsigned int scanned = 0;
    unsigned long sec, nsec, dest;
    struct vr_fragment *frag = *head, *next, **prev;

    prev = head;
    while (frag) {
        next = frag->f_next;

        vr_get_mono_time(&sec, &nsec);
        dest = frag->f_time + VR_ASSEMBLER_TIMEOUT_TIME;
        if (dest < frag->f_time) {
            if ((sec < frag->f_time) && (dest < sec)) {
                fragment_unlink_frag(prev, frag);
                fragment_free_frag(frag);
            } else {
                prev = &frag->f_next;
            }
        } else {
            if ((sec > dest) || (sec < frag->f_time)) {
                fragment_unlink_frag(prev, frag);
                fragment_free_frag(frag);
            } else {
                prev = &frag->f_next;
            }
        }
        scanned++;
        frag = next;
    }

    return scanned;
}
Esempio n. 3
0
static inline void
fragment_entry_set(struct vr_fragment *fe, unsigned short vrf, struct vr_ip *iph,
        unsigned short sport, unsigned short dport)
{
    unsigned long sec, nsec;

    fe->f_sip = iph->ip_saddr;
    fe->f_dip = iph->ip_daddr;
    fe->f_id = iph->ip_id;
    fe->f_vrf = vrf;
    fe->f_sport = sport;
    fe->f_dport = dport;
    vr_get_mono_time(&sec, &nsec);
    fe->f_time = sec;
    fe->f_expected = 0;
    fe->f_received = 0;

    return;
}
Esempio n. 4
0
static void
fragment_reap(struct vr_btable *table, int start,
        unsigned int num_entries)
{
    unsigned int i;
    struct vr_fragment *fe;
    unsigned long sec, nsec;

    vr_get_mono_time(&sec, &nsec);

    for (i = 0; i < ENTRIES_PER_SCAN; i++) {
        fe = vr_btable_get(table, (start + i) % num_entries);
        if (fe && fe->f_dip) {
            if (sec > fe->f_time + 1)
                vr_fragment_del(fe);
        }
    }


    return;
}
Esempio n. 5
0
struct vr_fragment *
vr_fragment_get(struct vrouter *router, unsigned short vrf, struct vr_ip *iph)
{
    unsigned int hash, index, i;
    struct vr_fragment_key key;
    struct vr_fragment *fe;
    unsigned long sec, nsec;

    fragment_key(&key, vrf, iph);
    hash = vr_hash(&key, sizeof(key), 0);
    index = (hash % FRAG_TABLE_ENTRIES) * FRAG_TABLE_BUCKETS;
    for (i = 0; i < FRAG_TABLE_BUCKETS; i++) {
        fe = fragment_entry_get(router, index + i);
        if (fe && !memcmp((const void *)&key, (const void *)&(fe->f_key),
                    sizeof(key)))
            break;
    }

    if (i == FRAG_TABLE_BUCKETS) {
        index = (hash % FRAG_OTABLE_ENTRIES);
        for (i = 0; i < FRAG_OTABLE_ENTRIES; i++) {
            fe = fragment_oentry_get(router, (index + i) % FRAG_OTABLE_ENTRIES);
            if (fe && !memcmp((const void *)&key, (const void *)&(fe->f_key),
                        sizeof(key)))
                break;
        }

        if (i == FRAG_OTABLE_ENTRIES)
            fe = NULL;
    }

    if (fe) {
        vr_get_mono_time(&sec, &nsec);
        fe->f_time = sec;
    }

    return fe;
}
Esempio n. 6
0
int
vr_fragment_assembler(struct vr_fragment **head_p,
        struct vr_fragment_queue_element *vfqe)
{
    int ret = 0;
    unsigned long sec, nsec;
    unsigned int list_length = 0, drop_reason;
    bool found = false, frag_head = false;

    struct vrouter *router;
    struct vr_ip *ip;
    struct vr_packet *pkt;
    struct vr_packet_node *pnode;
    struct vr_fragment *frag, *frag_flow, **prev = NULL;
    struct vr_fragment_queue_element *fqe;
    struct vr_fragment_key vfk;


    router = vfqe->fqe_router;
    pnode = &vfqe->fqe_pnode;
    pkt = pnode->pl_packet;
    ip = (struct vr_ip *)pkt_network_header(pkt);

    if (pnode->pl_flags & PN_FLAG_FRAGMENT_HEAD)
        frag_head = true;

    __fragment_key(&vfk, pnode->pl_vrf, pnode->pl_inner_src_ip,
            pnode->pl_inner_dst_ip, ip->ip_id);

    frag = *head_p;
    prev = head_p;
    while (frag) {
        list_length++;
        if (!memcmp(&frag->f_key, &vfk, sizeof(vfk))) {
            found = true;
            break;
        }

        prev = &frag->f_next;
        frag = frag->f_next;
    }

    if (!frag_head) {
        frag_flow = vr_fragment_get(router, pnode->pl_vrf, ip);
        if (frag_flow) {
            vr_fragment_flush_queue_element(vfqe);
            return 0;
        }
    }

    if (!found) {
        if (frag_head) {
            drop_reason = VP_DROP_CLONED_ORIGINAL;
            goto exit_assembly;
        }

        if (list_length > VR_MAX_FRAGMENTS_PER_ASSEMBLER_QUEUE) {
            drop_reason = VP_DROP_FRAGMENT_QUEUE_FAIL;
            goto exit_assembly;
        }

        frag = vr_zalloc(sizeof(*frag), VR_FRAGMENT_OBJECT);
        if (!frag) {
            ret = -ENOMEM;
            drop_reason = VP_DROP_NO_MEMORY;
            goto exit_assembly;
        }

        memcpy(&frag->f_key, &vfk, sizeof(vfk));
        frag->f_port_info_valid = false;
    }

    vr_get_mono_time(&sec, &nsec);
    frag->f_time = sec;
    if (!found) {
        prev = head_p;
        frag->f_next = *head_p;
        *head_p = frag;
    }

    if (!frag_head) {
        vfqe->fqe_next = NULL;
        fqe = frag->f_qe;
        if (!fqe) {
            frag->f_qe = vfqe;
        } else {
            while (fqe) {
                if (fqe->fqe_next) {
                    fqe = fqe->fqe_next;
                } else {
                    break;
                }
            }

            fqe->fqe_next = vfqe;
        }
    } else {
        frag->f_port_info_valid = true;
        vr_fragment_queue_element_free(vfqe, VP_DROP_CLONED_ORIGINAL);
    }


    if (frag->f_port_info_valid) {
        while ((fqe = frag->f_qe)) {
            frag->f_qe = fqe->fqe_next;
            vr_fragment_flush_queue_element(fqe);
        }

        fragment_unlink_frag(prev, frag);
        fragment_free_frag(frag);
    }

    return 0;

exit_assembly:
    vr_fragment_queue_element_free(vfqe, drop_reason);
    return ret;
}