X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fbond.c;h=c4cfa45b4e2d4ee7466dc1eed6d26257d8f6b912;hb=230f02bc4f892170747fcded9afb85be09360c1a;hp=dc0d76b580e7e79ea1a1a8237d9e8e50396c2a01;hpb=9a54394ac99e955cf23d8b45cc75ae08316a50f8;p=sliver-openvswitch.git diff --git a/ofproto/bond.c b/ofproto/bond.c index dc0d76b58..c4cfa45b4 100644 --- a/ofproto/bond.c +++ b/ofproto/bond.c @@ -23,6 +23,7 @@ #include #include +#include "connectivity.h" #include "coverage.h" #include "dynamic-string.h" #include "flow.h" @@ -34,6 +35,7 @@ #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" +#include "seq.h" #include "shash.h" #include "timeval.h" #include "unixctl.h" @@ -41,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 @@ -56,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. */ @@ -83,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; @@ -101,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); @@ -125,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 *, @@ -162,7 +175,7 @@ bond_mode_to_string(enum bond_mode balance) { case BM_AB: return "active-backup"; } - NOT_REACHED(); + OVS_NOT_REACHED(); } @@ -178,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; @@ -191,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; } @@ -203,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; } @@ -227,8 +233,10 @@ bond_unref(struct bond *bond) } hmap_destroy(&bond->slaves); + ovs_mutex_destroy(&bond->mutex); free(bond->hash); free(bond->name); + ovs_refcount_destroy(&bond->ref_cnt); free(bond); } @@ -441,7 +449,7 @@ bond_run(struct bond *bond, enum lacp_status lacp_status) /* Enable slaves based on link status and LACP feedback. */ HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) { bond_link_status_update(slave); - slave->change_seq = netdev_change_seq(slave->netdev); + slave->change_seq = seq_read(connectivity_seq_get()); } if (!bond->active_slave || !bond->active_slave->enabled) { bond_choose_active_slave(bond); @@ -472,9 +480,7 @@ bond_wait(struct bond *bond) poll_timer_wait_until(slave->delay_expires); } - if (slave->change_seq != netdev_change_seq(slave->netdev)) { - poll_immediate_wake(); - } + seq_wait(connectivity_seq_get(), slave->change_seq); } if (bond->next_fake_iface_update != LLONG_MAX) { @@ -549,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; @@ -647,7 +653,7 @@ bond_check_admissibility(struct bond *bond, const void *slave_, goto out; } - NOT_REACHED(); + OVS_NOT_REACHED(); out: ovs_rwlock_unlock(&rwlock); return verdict; @@ -1347,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"); } @@ -1422,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) @@ -1459,16 +1495,12 @@ 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; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } }