X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=lib%2Flacp.c;h=a3f72edd0be60ed605d39dd17050dc61837f1645;hb=1e827902be9194d71ea851c9ce2676f65eeed33a;hp=5d9085023a604c65cf435f5f7a6c81157d63b363;hpb=bbb8dee92d639331e8bd81823638267dcc895396;p=sliver-openvswitch.git diff --git a/lib/lacp.c b/lib/lacp.c index 5d9085023..a3f72edd0 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2012 Nicira, Inc. +/* Copyright (c) 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,14 @@ #include +#include "connectivity.h" #include "dynamic-string.h" #include "hash.h" #include "hmap.h" #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" +#include "seq.h" #include "shash.h" #include "timer.h" #include "timeval.h" @@ -102,8 +104,9 @@ struct lacp { bool fast; /* True if using fast probe interval. */ bool negotiated; /* True if LACP negotiations were successful. */ bool update; /* True if lacp_update() needs to be called. */ + bool fallback_ab; /* True if fallback to active-backup on LACP failure. */ - int ref_cnt; + struct ovs_refcount ref_cnt; }; struct slave { @@ -124,18 +127,25 @@ struct slave { struct timer rx; /* Expected message receive timer. */ }; -static struct list all_lacps = LIST_INITIALIZER(&all_lacps); - -static void lacp_update_attached(struct lacp *); - -static void slave_destroy(struct slave *); -static void slave_set_defaulted(struct slave *); -static void slave_set_expired(struct slave *); -static void slave_get_actor(struct slave *, struct lacp_info *actor); -static void slave_get_priority(struct slave *, struct lacp_info *priority); -static bool slave_may_tx(const struct slave *); -static struct slave *slave_lookup(const struct lacp *, const void *slave); -static bool info_tx_equal(struct lacp_info *, struct lacp_info *); +static struct ovs_mutex mutex; +static struct list all_lacps__ = LIST_INITIALIZER(&all_lacps__); +static struct list *const all_lacps OVS_GUARDED_BY(mutex) = &all_lacps__; + +static void lacp_update_attached(struct lacp *) OVS_REQUIRES(mutex); + +static void slave_destroy(struct slave *) OVS_REQUIRES(mutex); +static void slave_set_defaulted(struct slave *) OVS_REQUIRES(mutex); +static void slave_set_expired(struct slave *) OVS_REQUIRES(mutex); +static void slave_get_actor(struct slave *, struct lacp_info *actor) + OVS_REQUIRES(mutex); +static void slave_get_priority(struct slave *, struct lacp_info *priority) + OVS_REQUIRES(mutex); +static bool slave_may_tx(const struct slave *) + OVS_REQUIRES(mutex); +static struct slave *slave_lookup(const struct lacp *, const void *slave) + OVS_REQUIRES(mutex); +static bool info_tx_equal(struct lacp_info *, struct lacp_info *) + OVS_REQUIRES(mutex); static unixctl_cb_func lacp_unixctl_show; @@ -194,14 +204,23 @@ lacp_init(void) /* Creates a LACP object. */ struct lacp * -lacp_create(void) +lacp_create(void) OVS_EXCLUDED(mutex) { + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; struct lacp *lacp; + if (ovsthread_once_start(&once)) { + ovs_mutex_init_recursive(&mutex); + ovsthread_once_done(&once); + } + lacp = xzalloc(sizeof *lacp); hmap_init(&lacp->slaves); - list_push_back(&all_lacps, &lacp->node); - lacp->ref_cnt = 1; + ovs_refcount_init(&lacp->ref_cnt); + + ovs_mutex_lock(&mutex); + list_push_back(all_lacps, &lacp->node); + ovs_mutex_unlock(&mutex); return lacp; } @@ -210,24 +229,19 @@ lacp_ref(const struct lacp *lacp_) { struct lacp *lacp = CONST_CAST(struct lacp *, lacp_); if (lacp) { - ovs_assert(lacp->ref_cnt > 0); - lacp->ref_cnt++; + ovs_refcount_ref(&lacp->ref_cnt); } return lacp; } /* Destroys 'lacp' and its slaves. Does nothing if 'lacp' is NULL. */ void -lacp_unref(struct lacp *lacp) +lacp_unref(struct lacp *lacp) OVS_EXCLUDED(mutex) { - if (!lacp) { - return; - } - - ovs_assert(lacp->ref_cnt > 0); - if (!--lacp->ref_cnt) { + if (lacp && ovs_refcount_unref(&lacp->ref_cnt) == 1) { struct slave *slave, *next; + ovs_mutex_lock(&mutex); HMAP_FOR_EACH_SAFE (slave, next, node, &lacp->slaves) { slave_destroy(slave); } @@ -235,16 +249,20 @@ lacp_unref(struct lacp *lacp) hmap_destroy(&lacp->slaves); list_remove(&lacp->node); free(lacp->name); + ovs_refcount_destroy(&lacp->ref_cnt); free(lacp); + ovs_mutex_unlock(&mutex); } } /* Configures 'lacp' with settings from 's'. */ void lacp_configure(struct lacp *lacp, const struct lacp_settings *s) + OVS_EXCLUDED(mutex) { ovs_assert(!eth_addr_is_zero(s->id)); + ovs_mutex_lock(&mutex); if (!lacp->name || strcmp(s->name, lacp->name)) { free(lacp->name); lacp->name = xstrdup(s->name); @@ -259,14 +277,25 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s) lacp->active = s->active; lacp->fast = s->fast; + + if (lacp->fallback_ab != s->fallback_ab_cfg) { + lacp->fallback_ab = s->fallback_ab_cfg; + lacp->update = true; + } + + ovs_mutex_unlock(&mutex); } /* Returns true if 'lacp' is configured in active mode, false if 'lacp' is * configured for passive mode. */ bool -lacp_is_active(const struct lacp *lacp) +lacp_is_active(const struct lacp *lacp) OVS_EXCLUDED(mutex) { - return lacp->active; + bool ret; + ovs_mutex_lock(&mutex); + ret = lacp->active; + ovs_mutex_unlock(&mutex); + return ret; } /* Processes 'packet' which was received on 'slave_'. This function should be @@ -275,20 +304,23 @@ lacp_is_active(const struct lacp *lacp) void lacp_process_packet(struct lacp *lacp, const void *slave_, const struct ofpbuf *packet) + OVS_EXCLUDED(mutex) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - struct slave *slave = slave_lookup(lacp, slave_); const struct lacp_pdu *pdu; long long int tx_rate; + struct slave *slave; + ovs_mutex_lock(&mutex); + slave = slave_lookup(lacp, slave_); if (!slave) { - return; + goto out; } pdu = parse_lacp_packet(packet); if (!pdu) { VLOG_WARN_RL(&rl, "%s: received an unparsable LACP PDU.", lacp->name); - return; + goto out; } slave->status = LACP_CURRENT; @@ -304,19 +336,27 @@ lacp_process_packet(struct lacp *lacp, const void *slave_, lacp->update = true; slave->partner = pdu->actor; } + +out: + ovs_mutex_unlock(&mutex); } /* Returns the lacp_status of the given 'lacp' object (which may be NULL). */ enum lacp_status -lacp_status(const struct lacp *lacp) +lacp_status(const struct lacp *lacp) OVS_EXCLUDED(mutex) { + enum lacp_status ret; + + ovs_mutex_lock(&mutex); if (!lacp) { - return LACP_DISABLED; + ret = LACP_DISABLED; } else if (lacp->negotiated) { - return LACP_NEGOTIATED; + ret = LACP_NEGOTIATED; } else { - return LACP_CONFIGURED; + ret = LACP_CONFIGURED; } + ovs_mutex_unlock(&mutex); + return ret; } /* Registers 'slave_' as subordinate to 'lacp'. This should be called at least @@ -325,9 +365,12 @@ lacp_status(const struct lacp *lacp) void lacp_slave_register(struct lacp *lacp, void *slave_, const struct lacp_slave_settings *s) + OVS_EXCLUDED(mutex) { - struct slave *slave = slave_lookup(lacp, slave_); + struct slave *slave; + ovs_mutex_lock(&mutex); + slave = slave_lookup(lacp, slave_); if (!slave) { slave = xzalloc(sizeof *slave); slave->lacp = lacp; @@ -358,44 +401,58 @@ lacp_slave_register(struct lacp *lacp, void *slave_, slave_set_expired(slave); } } + ovs_mutex_unlock(&mutex); } /* Unregisters 'slave_' with 'lacp'. */ void lacp_slave_unregister(struct lacp *lacp, const void *slave_) + OVS_EXCLUDED(mutex) { - struct slave *slave = slave_lookup(lacp, slave_); + struct slave *slave; + ovs_mutex_lock(&mutex); + slave = slave_lookup(lacp, slave_); if (slave) { slave_destroy(slave); lacp->update = true; } + ovs_mutex_unlock(&mutex); } /* This function should be called whenever the carrier status of 'slave_' has * changed. If 'lacp' is null, this function has no effect.*/ void lacp_slave_carrier_changed(const struct lacp *lacp, const void *slave_) + OVS_EXCLUDED(mutex) { - if (lacp) { - struct slave *slave = slave_lookup(lacp, slave_); + struct slave *slave; + if (!lacp) { + return; + } - if (!slave) { - return; - } + ovs_mutex_lock(&mutex); + slave = slave_lookup(lacp, slave_); + if (!slave) { + goto out; + } - if (slave->status == LACP_CURRENT || slave->lacp->active) { - slave_set_expired(slave); - } + if (slave->status == LACP_CURRENT || slave->lacp->active) { + slave_set_expired(slave); } + +out: + ovs_mutex_unlock(&mutex); } static bool -slave_may_enable__(struct slave *slave) +slave_may_enable__(struct slave *slave) OVS_REQUIRES(mutex) { /* The slave may be enabled if it's attached to an aggregator and its * partner is synchronized.*/ - return slave->attached && (slave->partner.state & LACP_STATE_SYNC); + return slave->attached && (slave->partner.state & LACP_STATE_SYNC + || (slave->lacp && slave->lacp->fallback_ab + && slave->status == LACP_DEFAULTED)); } /* This function should be called before enabling 'slave_' to send or receive @@ -403,10 +460,17 @@ slave_may_enable__(struct slave *slave) * convenience, returns true if 'lacp' is NULL. */ bool lacp_slave_may_enable(const struct lacp *lacp, const void *slave_) + OVS_EXCLUDED(mutex) { if (lacp) { - struct slave *slave = slave_lookup(lacp, slave_); - return slave ? slave_may_enable__(slave) : false; + struct slave *slave; + bool ret; + + ovs_mutex_lock(&mutex); + slave = slave_lookup(lacp, slave_); + ret = slave ? slave_may_enable__(slave) : false; + ovs_mutex_unlock(&mutex); + return ret; } else { return true; } @@ -417,24 +481,37 @@ lacp_slave_may_enable(const struct lacp *lacp, const void *slave_) * misconfigured (or broken) partner. */ bool lacp_slave_is_current(const struct lacp *lacp, const void *slave_) + OVS_EXCLUDED(mutex) { - struct slave *slave = slave_lookup(lacp, slave_); - return slave ? slave->status != LACP_DEFAULTED : false; + struct slave *slave; + bool ret; + + ovs_mutex_lock(&mutex); + slave = slave_lookup(lacp, slave_); + ret = slave ? slave->status != LACP_DEFAULTED : false; + ovs_mutex_unlock(&mutex); + return ret; } /* This function should be called periodically to update 'lacp'. */ void -lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) +lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex) { struct slave *slave; + ovs_mutex_lock(&mutex); HMAP_FOR_EACH (slave, node, &lacp->slaves) { if (timer_expired(&slave->rx)) { + enum slave_status old_status = slave->status; + if (slave->status == LACP_CURRENT) { slave_set_expired(slave); } else if (slave->status == LACP_EXPIRED) { slave_set_defaulted(slave); } + if (slave->status != old_status) { + seq_change(connectivity_seq_get()); + } } } @@ -465,16 +542,19 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) : LACP_SLOW_TIME_TX); timer_set_duration(&slave->tx, duration); + seq_change(connectivity_seq_get()); } } + ovs_mutex_unlock(&mutex); } /* Causes poll_block() to wake up when lacp_run() needs to be called again. */ void -lacp_wait(struct lacp *lacp) +lacp_wait(struct lacp *lacp) OVS_EXCLUDED(mutex) { struct slave *slave; + ovs_mutex_lock(&mutex); HMAP_FOR_EACH (slave, node, &lacp->slaves) { if (slave_may_tx(slave)) { timer_wait(&slave->tx); @@ -484,6 +564,7 @@ lacp_wait(struct lacp *lacp) timer_wait(&slave->rx); } } + ovs_mutex_unlock(&mutex); } /* Static Helpers. */ @@ -491,7 +572,7 @@ lacp_wait(struct lacp *lacp) /* Updates the attached status of all slaves controlled by 'lacp' and sets its * negotiated parameter to true if any slaves are attachable. */ static void -lacp_update_attached(struct lacp *lacp) +lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex) { struct slave *lead, *slave; struct lacp_info lead_pri; @@ -514,6 +595,9 @@ lacp_update_attached(struct lacp *lacp) } if (slave->status == LACP_DEFAULTED) { + if (lacp->fallback_ab) { + slave->attached = true; + } continue; } @@ -530,7 +614,8 @@ lacp_update_attached(struct lacp *lacp) if (lead) { HMAP_FOR_EACH (slave, node, &lacp->slaves) { - if (lead->partner.key != slave->partner.key + if ((lacp->fallback_ab && slave->status == LACP_DEFAULTED) + || lead->partner.key != slave->partner.key || !eth_addr_equals(lead->partner.sys_id, slave->partner.sys_id)) { slave->attached = false; @@ -540,7 +625,7 @@ lacp_update_attached(struct lacp *lacp) } static void -slave_destroy(struct slave *slave) +slave_destroy(struct slave *slave) OVS_REQUIRES(mutex) { if (slave) { struct lacp *lacp = slave->lacp; @@ -564,7 +649,7 @@ slave_destroy(struct slave *slave) } static void -slave_set_defaulted(struct slave *slave) +slave_set_defaulted(struct slave *slave) OVS_REQUIRES(mutex) { memset(&slave->partner, 0, sizeof slave->partner); @@ -573,7 +658,7 @@ slave_set_defaulted(struct slave *slave) } static void -slave_set_expired(struct slave *slave) +slave_set_expired(struct slave *slave) OVS_REQUIRES(mutex) { slave->status = LACP_EXPIRED; slave->partner.state |= LACP_STATE_TIME; @@ -584,6 +669,7 @@ slave_set_expired(struct slave *slave) static void slave_get_actor(struct slave *slave, struct lacp_info *actor) + OVS_REQUIRES(mutex) { struct lacp *lacp = slave->lacp; uint16_t key; @@ -636,6 +722,7 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor) * link. */ static void slave_get_priority(struct slave *slave, struct lacp_info *priority) + OVS_REQUIRES(mutex) { uint16_t partner_priority, actor_priority; @@ -660,13 +747,13 @@ slave_get_priority(struct slave *slave, struct lacp_info *priority) } static bool -slave_may_tx(const struct slave *slave) +slave_may_tx(const struct slave *slave) OVS_REQUIRES(mutex) { return slave->lacp->active || slave->status != LACP_DEFAULTED; } static struct slave * -slave_lookup(const struct lacp *lacp, const void *slave_) +slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQUIRES(mutex) { struct slave *slave; @@ -703,11 +790,11 @@ info_tx_equal(struct lacp_info *a, struct lacp_info *b) } static struct lacp * -lacp_find(const char *name) +lacp_find(const char *name) OVS_REQUIRES(mutex) { struct lacp *lacp; - LIST_FOR_EACH (lacp, node, &all_lacps) { + LIST_FOR_EACH (lacp, node, all_lacps) { if (!strcmp(lacp->name, name)) { return lacp; } @@ -753,7 +840,7 @@ ds_put_lacp_state(struct ds *ds, uint8_t state) } static void -lacp_print_details(struct ds *ds, struct lacp *lacp) +lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex) { struct shash slave_shash = SHASH_INITIALIZER(&slave_shash); const struct shash_node **sorted_slaves = NULL; @@ -809,7 +896,7 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) status = "defaulted"; break; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } ds_put_format(ds, "\nslave: %s: %s %s\n", slave->name, status, @@ -854,24 +941,28 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) static void lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], - void *aux OVS_UNUSED) + void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; struct lacp *lacp; + ovs_mutex_lock(&mutex); if (argc > 1) { lacp = lacp_find(argv[1]); if (!lacp) { unixctl_command_reply_error(conn, "no such lacp object"); - return; + goto out; } lacp_print_details(&ds, lacp); } else { - LIST_FOR_EACH (lacp, node, &all_lacps) { + LIST_FOR_EACH (lacp, node, all_lacps) { lacp_print_details(&ds, lacp); } } unixctl_command_reply(conn, ds_cstr(&ds)); ds_destroy(&ds); + +out: + ovs_mutex_unlock(&mutex); }