X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fbond.c;h=c4cfa45b4e2d4ee7466dc1eed6d26257d8f6b912;hb=d2ad7ef178c39427f2e93ea5c70b3ffc51b7ad1f;hp=3b0c11c93031b16ce7eb35ff3e1904a3bd7b2e4a;hpb=c5f81b20da9bbf0ac406a88718597a4e84729a98;p=sliver-openvswitch.git diff --git a/ofproto/bond.c b/ofproto/bond.c index 3b0c11c93..c4cfa45b4 100644 --- a/ofproto/bond.c +++ b/ofproto/bond.c @@ -43,6 +43,10 @@ VLOG_DEFINE_THIS_MODULE(bond); +static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER; +static struct hmap all_bonds__ = HMAP_INITIALIZER(&all_bonds__); +static struct hmap *const all_bonds OVS_GUARDED_BY(rwlock) = &all_bonds__; + /* Bit-mask for hashing a flow down to a bucket. * There are (BOND_MASK + 1) buckets. */ #define BOND_MASK 0xff @@ -58,6 +62,7 @@ struct bond_entry { /* A bond slave, that is, one of the links comprising a bond. */ struct bond_slave { struct hmap_node hmap_node; /* In struct bond's slaves hmap. */ + struct list list_node; /* In struct bond's enabled_slaves list. */ struct bond *bond; /* The bond that contains this slave. */ void *aux; /* Client-provided handle for this slave. */ @@ -85,6 +90,14 @@ struct bond { /* Slaves. */ struct hmap slaves; + /* Enabled slaves. + * + * Any reader or writer of 'enabled_slaves' must hold 'mutex'. + * (To prevent the bond_slave from disappearing they must also hold + * 'rwlock'.) */ + struct ovs_mutex mutex OVS_ACQ_AFTER(rwlock); + struct list enabled_slaves OVS_GUARDED; /* Contains struct bond_slaves. */ + /* Bonding info. */ enum bond_mode balance; /* Balancing mode, one of BM_*. */ struct bond_slave *active_slave; @@ -103,13 +116,9 @@ struct bond { long long int next_fake_iface_update; /* LLONG_MAX if disabled. */ bool lacp_fallback_ab; /* Fallback to active-backup on LACP failure. */ - atomic_int ref_cnt; + struct ovs_refcount ref_cnt; }; -static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER; -static struct hmap all_bonds__ = HMAP_INITIALIZER(&all_bonds__); -static struct hmap *const all_bonds OVS_GUARDED_BY(rwlock) = &all_bonds__; - static void bond_entry_reset(struct bond *) OVS_REQ_WRLOCK(rwlock); static struct bond_slave *bond_slave_lookup(struct bond *, const void *slave_) OVS_REQ_RDLOCK(rwlock); @@ -127,6 +136,8 @@ static struct bond_entry *lookup_bond_entry(const struct bond *, const struct flow *, uint16_t vlan) OVS_REQ_RDLOCK(rwlock); +static struct bond_slave *get_enabled_slave(struct bond *) + OVS_REQ_RDLOCK(rwlock); static struct bond_slave *choose_output_slave(const struct bond *, const struct flow *, struct flow_wildcards *, @@ -180,8 +191,10 @@ bond_create(const struct bond_settings *s) bond = xzalloc(sizeof *bond); hmap_init(&bond->slaves); + list_init(&bond->enabled_slaves); + ovs_mutex_init(&bond->mutex); bond->next_fake_iface_update = LLONG_MAX; - atomic_init(&bond->ref_cnt, 1); + ovs_refcount_init(&bond->ref_cnt); bond_reconfigure(bond, s); return bond; @@ -193,9 +206,7 @@ bond_ref(const struct bond *bond_) struct bond *bond = CONST_CAST(struct bond *, bond_); if (bond) { - int orig; - atomic_add(&bond->ref_cnt, 1, &orig); - ovs_assert(orig > 0); + ovs_refcount_ref(&bond->ref_cnt); } return bond; } @@ -205,15 +216,8 @@ void bond_unref(struct bond *bond) { struct bond_slave *slave, *next_slave; - int orig; - - if (!bond) { - return; - } - atomic_sub(&bond->ref_cnt, 1, &orig); - ovs_assert(orig > 0); - if (orig != 1) { + if (!bond || ovs_refcount_unref(&bond->ref_cnt) != 1) { return; } @@ -229,9 +233,10 @@ bond_unref(struct bond *bond) } hmap_destroy(&bond->slaves); + ovs_mutex_destroy(&bond->mutex); free(bond->hash); free(bond->name); - atomic_destroy(&bond->ref_cnt); + ovs_refcount_destroy(&bond->ref_cnt); free(bond); } @@ -550,7 +555,7 @@ bond_compose_learning_packet(struct bond *bond, packet = ofpbuf_new(0); compose_rarp(packet, eth_src); if (vlan) { - eth_push_vlan(packet, htons(vlan)); + eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(vlan)); } *port_aux = slave->aux; @@ -1348,6 +1353,15 @@ bond_enable_slave(struct bond_slave *slave, bool enable) if (enable != slave->enabled) { slave->bond->bond_revalidate = true; slave->enabled = enable; + + ovs_mutex_lock(&slave->bond->mutex); + if (enable) { + list_insert(&slave->bond->enabled_slaves, &slave->list_node); + } else { + list_remove(&slave->list_node); + } + ovs_mutex_unlock(&slave->bond->mutex); + VLOG_INFO("interface %s: %s", slave->name, slave->enabled ? "enabled" : "disabled"); } @@ -1423,6 +1437,27 @@ lookup_bond_entry(const struct bond *bond, const struct flow *flow, return &bond->hash[bond_hash(bond, flow, vlan) & BOND_MASK]; } +/* Selects and returns an enabled slave from the 'enabled_slaves' list + * in a round-robin fashion. If the 'enabled_slaves' list is empty, + * returns NULL. */ +static struct bond_slave * +get_enabled_slave(struct bond *bond) +{ + struct list *node; + + ovs_mutex_lock(&bond->mutex); + if (list_is_empty(&bond->enabled_slaves)) { + ovs_mutex_unlock(&bond->mutex); + return NULL; + } + + node = list_pop_front(&bond->enabled_slaves); + list_push_back(&bond->enabled_slaves, node); + ovs_mutex_unlock(&bond->mutex); + + return CONTAINER_OF(node, struct bond_slave, list_node); +} + static struct bond_slave * choose_output_slave(const struct bond *bond, const struct flow *flow, struct flow_wildcards *wc, uint16_t vlan) @@ -1460,11 +1495,7 @@ choose_output_slave(const struct bond *bond, const struct flow *flow, } e = lookup_bond_entry(bond, flow, vlan); if (!e->slave || !e->slave->enabled) { - e->slave = CONTAINER_OF(hmap_random_node(&bond->slaves), - struct bond_slave, hmap_node); - if (!e->slave->enabled) { - e->slave = bond->active_slave; - } + e->slave = get_enabled_slave(CONST_CAST(struct bond*, bond)); } return e->slave;