Exemple #1
0
/* Attempts to make 'ml' learn from the fact that a frame from 'src_mac' was
 * just observed arriving from 'src_port' on the given 'vlan'.
 *
 * Returns nonzero if we actually learned something from this, zero if it just
 * confirms what we already knew.  The nonzero return value is the tag of flows
 * that now need revalidation.
 *
 * The 'vlan' parameter is used to maintain separate per-VLAN learning tables.
 * Specify 0 if this behavior is undesirable.
 *
 * 'lock_type' specifies whether the entry should be locked or existing locks
 * are check. */
tag_type
mac_learning_learn(struct mac_learning *ml,
                   const uint8_t src_mac[ETH_ADDR_LEN], uint16_t vlan,
                   uint16_t src_port, enum grat_arp_lock_type lock_type)
{
    struct mac_entry *e;
    struct list *bucket;

    if (!is_learning_vlan(ml, vlan)) {
        return 0;
    }

    if (eth_addr_is_multicast(src_mac)) {
        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 30);
        VLOG_DBG_RL(&rl, "multicast packet source "ETH_ADDR_FMT,
                    ETH_ADDR_ARGS(src_mac));
        return 0;
    }

    bucket = mac_table_bucket(ml, src_mac, vlan);
    e = search_bucket(bucket, src_mac, vlan);
    if (!e) {
        if (!list_is_empty(&ml->free)) {
            e = mac_entry_from_lru_node(ml->free.next);
        } else {
            e = mac_entry_from_lru_node(ml->lrus.next);
            list_remove(&e->hash_node);
        }
        memcpy(e->mac, src_mac, ETH_ADDR_LEN);
        list_push_front(bucket, &e->hash_node);
        e->port = -1;
        e->vlan = vlan;
        e->tag = make_unknown_mac_tag(ml, src_mac, vlan);
        e->grat_arp_lock = TIME_MIN;
    }

    if (lock_type != GRAT_ARP_LOCK_CHECK || time_now() >= e->grat_arp_lock) {
        /* Make the entry most-recently-used. */
        list_remove(&e->lru_node);
        list_push_back(&ml->lrus, &e->lru_node);
        e->expires = time_now() + MAC_ENTRY_IDLE_TIME;
        if (lock_type == GRAT_ARP_LOCK_SET) {
            e->grat_arp_lock = time_now() + MAC_GRAT_ARP_LOCK_TIME;
        }

        /* Did we learn something? */
        if (e->port != src_port) {
            tag_type old_tag = e->tag;
            e->port = src_port;
            e->tag = tag_create_random();
            COVERAGE_INC(mac_learning_learned);
            return old_tag;
        }
    }

    return 0;
}
static Block_t *
get_free_block(Allctr_t *allctr, Uint size,
	       Block_t *cand_blk, Uint cand_size)
{
    GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
    int unsafe_bi, min_bi;
    Block_t *blk;

    ASSERT(!cand_blk || cand_size >= size);

    unsafe_bi = BKT_IX(gfallctr, size);
    
    min_bi = find_bucket(&gfallctr->bucket_mask, unsafe_bi);
    if (min_bi < 0)
	return NULL;

    if (min_bi == unsafe_bi) {
	blk = search_bucket(allctr, min_bi, size);
	if (blk) {
	    if (cand_blk && cand_size <= MBC_FBLK_SZ(blk))
		return NULL; /* cand_blk was better */
	    unlink_free_block(allctr, blk);
	    return blk;
	}
	if (min_bi < NO_OF_BKTS - 1) {
	    min_bi = find_bucket(&gfallctr->bucket_mask, min_bi + 1);
	    if (min_bi < 0)
		return NULL;
	}
	else
	    return NULL;
    }
    else {
	ASSERT(min_bi > unsafe_bi);
    }

    /* We are guaranteed to find a block that fits in this bucket */
    blk = search_bucket(allctr, min_bi, size);
    ASSERT(blk);
    if (cand_blk && cand_size <= MBC_FBLK_SZ(blk))
	return NULL; /* cand_blk was better */
    unlink_free_block(allctr, blk);
    return blk;
}
Exemple #3
0
/* Looks up MAC 'dst' for VLAN 'vlan' in 'ml'.  Returns the port on which a
 * frame destined for 'dst' should be sent, -1 if unknown.
 *
 * Adds to '*tag' (which the caller must have initialized) the tag that should
 * be attached to any flow created based on the return value, if any, to allow
 * those flows to be revalidated when the MAC learning entry changes.
 *
 * 'is_grat_arp_locked' is an optional parameter that returns whether the entry
 * is currently locked.*/
int
mac_learning_lookup_tag(const struct mac_learning *ml,
                        const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan,
                        tag_type *tag, bool *is_grat_arp_locked)
{
    if (eth_addr_is_multicast(dst) || !is_learning_vlan(ml, vlan)) {
        return -1;
    } else {
        struct mac_entry *e = search_bucket(mac_table_bucket(ml, dst, vlan),
                                            dst, vlan);
        if (e) {
            *tag |= e->tag;

            if (is_grat_arp_locked) {
                *is_grat_arp_locked = time_now() < e->grat_arp_lock;
            }

            return e->port;
        } else {
            *tag |= make_unknown_mac_tag(ml, dst, vlan);
            return -1;
        }
    }
}