X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Flacp.c;h=a7f66a24ab0c2e8e1f282c49c6f77a341238f61f;hb=b0387df4e0ac796af05765834bb6e7750b8b6ae6;hp=de860e0d96c9f795e413d2cbb2a1f920153d5e8d;hpb=77fdfa9bf71aff101219b249955842f6dc59b5c9;p=openvswitch diff --git a/lib/lacp.c b/lib/lacp.c index de860e0d..a7f66a24 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -25,6 +25,7 @@ #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" +#include "timer.h" #include "timeval.h" #include "unixctl.h" #include "vlog.h" @@ -47,6 +48,9 @@ struct lacp { struct hmap slaves; /* Slaves this LACP object controls. */ struct slave *key_slave; /* Slave whose ID will be the aggregation key. */ + enum lacp_time lacp_time; /* Fast, Slow or Custom LACP time. */ + long long int custom_time; /* LACP_TIME_CUSTOM transmission rate. */ + bool strict; /* True if in strict mode. */ bool negotiated; /* True if LACP negotiations were successful. */ bool update; /* True if lacp_update() needs to be called. */ }; @@ -62,11 +66,10 @@ struct slave { enum slave_status status; /* Slave status. */ bool attached; /* Attached. Traffic may flow. */ - bool enabled; /* Enabled. Traffic is flowing. */ struct lacp_info partner; /* Partner information. */ struct lacp_info ntt_actor; /* Used to decide if we Need To Transmit. */ - long long int tx; /* Next message transmission time. */ - long long int rx; /* Expected message receive time. */ + struct timer tx; /* Next message transmission timer. */ + struct timer rx; /* Expected message receive timer. */ }; static struct list all_lacps = LIST_INITIALIZER(&all_lacps); @@ -85,6 +88,51 @@ static bool info_tx_equal(struct lacp_info *, struct lacp_info *); static void lacp_unixctl_show(struct unixctl_conn *, const char *args, void *aux); +/* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */ +void +compose_lacp_pdu(const struct lacp_info *actor, + const struct lacp_info *partner, struct lacp_pdu *pdu) +{ + memset(pdu, 0, sizeof *pdu); + + pdu->subtype = 1; + pdu->version = 1; + + pdu->actor_type = 1; + pdu->actor_len = 20; + pdu->actor = *actor; + + pdu->partner_type = 2; + pdu->partner_len = 20; + pdu->partner = *partner; + + pdu->collector_type = 3; + pdu->collector_len = 16; + pdu->collector_delay = htons(0); +} + +/* Parses 'b' which represents a packet containing a LACP PDU. This function + * returns NULL if 'b' is malformed, or does not represent a LACP PDU format + * supported by OVS. Otherwise, it returns a pointer to the lacp_pdu contained + * within 'b'. */ +const struct lacp_pdu * +parse_lacp_packet(const struct ofpbuf *b) +{ + const struct lacp_pdu *pdu; + + pdu = ofpbuf_at(b, (uint8_t *)b->l3 - (uint8_t *)b->data, LACP_PDU_LEN); + + if (pdu && pdu->subtype == 1 + && pdu->actor_type == 1 && pdu->actor_len == 20 + && pdu->partner_type == 2 && pdu->partner_len == 20) { + return pdu; + } else { + return NULL; + } +} + +/* LACP Protocol Implementation. */ + /* Initializes the lacp module. */ void lacp_init(void) @@ -122,21 +170,35 @@ lacp_destroy(struct lacp *lacp) } } -/* Configures 'lacp' with the given 'name', 'sys_id', 'sys_priority', and - * 'active' parameters. */ +/* Configures 'lacp' with settings from 's'. */ void -lacp_configure(struct lacp *lacp, const char *name, - uint8_t sys_id[ETH_ADDR_LEN], uint16_t sys_priority, - bool active) +lacp_configure(struct lacp *lacp, const struct lacp_settings *s) { - if (!lacp->name || strcmp(name, lacp->name)) { + if (!lacp->name || strcmp(s->name, lacp->name)) { free(lacp->name); - lacp->name = xstrdup(name); + lacp->name = xstrdup(s->name); } - memcpy(lacp->sys_id, sys_id, ETH_ADDR_LEN); - lacp->sys_priority = sys_priority; - lacp->active = active; + if (!eth_addr_equals(lacp->sys_id, s->id) + || lacp->sys_priority != s->priority + || lacp->strict != s->strict) { + memcpy(lacp->sys_id, s->id, ETH_ADDR_LEN); + lacp->sys_priority = s->priority; + lacp->strict = s->strict; + lacp->update = true; + } + + lacp->active = s->active; + lacp->lacp_time = s->lacp_time; + lacp->custom_time = MAX(TIME_UPDATE_INTERVAL, s->custom_time); +} + +/* 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) +{ + return lacp->active; } /* Processes 'pdu', a parsed LACP packet received on 'slave_'. This function @@ -147,9 +209,23 @@ lacp_process_pdu(struct lacp *lacp, const void *slave_, const struct lacp_pdu *pdu) { struct slave *slave = slave_lookup(lacp, slave_); + long long int tx_rate; + + switch (lacp->lacp_time) { + case LACP_TIME_FAST: + tx_rate = LACP_FAST_TIME_TX; + break; + case LACP_TIME_SLOW: + tx_rate = LACP_SLOW_TIME_TX; + break; + case LACP_TIME_CUSTOM: + tx_rate = lacp->custom_time; + break; + default: NOT_REACHED(); + } slave->status = LACP_CURRENT; - slave->rx = time_msec() + LACP_SLOW_TIME_RX; + timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * tx_rate); slave->ntt_actor = pdu->partner; @@ -172,10 +248,10 @@ lacp_negotiated(const struct lacp *lacp) /* Registers 'slave_' as subordinate to 'lacp'. This should be called at least * once per slave in a LACP managed bond. Should also be called whenever a - * slave's name, port_id, or port_priority change. */ + * slave's settings change. */ void -lacp_slave_register(struct lacp *lacp, void *slave_, const char *name, - uint16_t port_id, uint16_t port_priority) +lacp_slave_register(struct lacp *lacp, void *slave_, + const struct lacp_slave_settings *s) { struct slave *slave = slave_lookup(lacp, slave_); @@ -191,15 +267,14 @@ lacp_slave_register(struct lacp *lacp, void *slave_, const char *name, } } - if (!slave->name || strcmp(name, slave->name)) { + if (!slave->name || strcmp(s->name, slave->name)) { free(slave->name); - slave->name = xstrdup(name); + slave->name = xstrdup(s->name); } - if (slave->port_id != port_id || slave->port_priority != port_priority) { - - slave->port_id = port_id; - slave->port_priority = port_priority; + if (slave->port_id != s->id || slave->port_priority != s->priority) { + slave->port_id = s->id; + slave->port_priority = s->priority; lacp->update = true; @@ -217,19 +292,10 @@ lacp_slave_unregister(struct lacp *lacp, const void *slave_) if (slave) { slave_destroy(slave); + lacp->update = true; } } -/* Should be called regularly to indicate whether 'slave_' is enabled. An - * enabled slave is allowed to send and receive traffic. Generally a slave - * should not be enabled if its carrier is down, or lacp_slave_may_enable() - * indicates it should not be enabled. */ -void -lacp_slave_enable(struct lacp *lacp, void *slave_, bool enabled) -{ - slave_lookup(lacp, slave_)->enabled = enabled; -} - /* This function should be called whenever the carrier status of 'slave_' has * changed. */ void @@ -263,6 +329,23 @@ lacp_slave_may_enable(const struct lacp *lacp, const void *slave_) } } +/* Returns the port ID used for 'slave_' in LACP communications. */ +uint16_t +lacp_slave_get_port_id(const struct lacp *lacp, const void *slave_) +{ + struct slave *slave = slave_lookup(lacp, slave_); + return slave->port_id; +} + +/* Returns true if partner information on 'slave_' is up to date. 'slave_' + * not being current, generally indicates a connectivity problem, or a + * misconfigured (or broken) partner. */ +bool +lacp_slave_is_current(const struct lacp *lacp, const void *slave_) +{ + return slave_lookup(lacp, slave_)->status == LACP_CURRENT; +} + /* This function should be called periodically to update 'lacp'. */ void lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) @@ -270,7 +353,7 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) struct slave *slave; HMAP_FOR_EACH (slave, node, &lacp->slaves) { - if (time_msec() >= slave->rx) { + if (timer_expired(&slave->rx)) { if (slave->status == LACP_CURRENT) { slave_set_expired(slave); } else if (slave->status == LACP_EXPIRED) { @@ -293,17 +376,23 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) slave_get_actor(slave, &actor); - if (time_msec() >= slave->tx + if (timer_expired(&slave->tx) || !info_tx_equal(&actor, &slave->ntt_actor)) { + long long int duration; slave->ntt_actor = actor; compose_lacp_pdu(&actor, &slave->partner, &pdu); send_pdu(slave->aux, &pdu); - slave->tx = time_msec() + - (slave->partner.state & LACP_STATE_TIME - ? LACP_FAST_TIME_TX - : LACP_SLOW_TIME_TX); + if (lacp->lacp_time == LACP_TIME_CUSTOM) { + duration = lacp->custom_time; + } else { + duration = (slave->partner.state & LACP_STATE_TIME + ? LACP_FAST_TIME_TX + : LACP_SLOW_TIME_TX); + } + + timer_set_duration(&slave->tx, duration); } } } @@ -316,18 +405,18 @@ lacp_wait(struct lacp *lacp) HMAP_FOR_EACH (slave, node, &lacp->slaves) { if (slave_may_tx(slave)) { - poll_timer_wait_until(slave->tx); + timer_wait(&slave->tx); } if (slave->status != LACP_DEFAULTED) { - poll_timer_wait_until(slave->rx); + timer_wait(&slave->rx); } } } /* Static Helpers. */ -/* Updates the attached status of all slaves controlled b 'lacp' and sets its +/* 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) @@ -376,6 +465,10 @@ lacp_update_attached(struct lacp *lacp) slave->attached = false; } } + } else if (lacp->strict) { + HMAP_FOR_EACH (slave, node, &lacp->slaves) { + slave->attached = false; + } } } @@ -415,11 +508,18 @@ slave_set_defaulted(struct slave *slave) static void slave_set_expired(struct slave *slave) { + struct lacp *lacp = slave->lacp; + slave->status = LACP_EXPIRED; slave->partner.state |= LACP_STATE_TIME; slave->partner.state &= ~LACP_STATE_SYNC; - slave->rx = time_msec() + LACP_FAST_TIME_RX; + /* The spec says we should wait LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX. + * This doesn't make sense when using custom times which can be much + * smaller than LACP_FAST_TIME. */ + timer_set_duration(&slave->rx, (lacp->lacp_time == LACP_TIME_CUSTOM + ? lacp->custom_time + : LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX)); } static void @@ -431,6 +531,10 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor) state |= LACP_STATE_ACT; } + if (slave->lacp->lacp_time != LACP_TIME_SLOW) { + state |= LACP_STATE_TIME; + } + if (slave->attached) { state |= LACP_STATE_SYNC; } @@ -447,7 +551,7 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor) state |= LACP_STATE_AGG; } - if (slave->enabled) { + if (slave->attached || !slave->lacp->negotiated) { state |= LACP_STATE_COL | LACP_STATE_DIST; } @@ -596,9 +700,16 @@ lacp_unixctl_show(struct unixctl_conn *conn, } ds_put_format(&ds, "lacp: %s\n", lacp->name); - ds_put_format(&ds, "\tstatus: %s %s\n", - lacp->active ? "active" : "passive", - lacp->negotiated ? "negotiated" : ""); + + ds_put_format(&ds, "\tstatus: %s", lacp->active ? "active" : "passive"); + if (lacp->strict) { + ds_put_cstr(&ds, " strict"); + } + if (lacp->negotiated) { + ds_put_cstr(&ds, " negotiated"); + } + ds_put_cstr(&ds, "\n"); + ds_put_format(&ds, "\tsys_id: " ETH_ADDR_FMT "\n", ETH_ADDR_ARGS(lacp->sys_id)); ds_put_format(&ds, "\tsys_priority: %u\n", lacp->sys_priority); ds_put_cstr(&ds, "\taggregation key: "); @@ -609,6 +720,21 @@ lacp_unixctl_show(struct unixctl_conn *conn, } ds_put_cstr(&ds, "\n"); + ds_put_cstr(&ds, "\tlacp_time: "); + switch (lacp->lacp_time) { + case LACP_TIME_FAST: + ds_put_cstr(&ds, "fast\n"); + break; + case LACP_TIME_SLOW: + ds_put_cstr(&ds, "slow\n"); + break; + case LACP_TIME_CUSTOM: + ds_put_format(&ds, "custom (%lld)\n", lacp->custom_time); + break; + default: + ds_put_cstr(&ds, "unknown\n"); + } + HMAP_FOR_EACH (slave, node, &lacp->slaves) { char *status; struct lacp_info actor; @@ -628,9 +754,8 @@ lacp_unixctl_show(struct unixctl_conn *conn, NOT_REACHED(); } - ds_put_format(&ds, "\nslave: %s: %s %s %s\n", slave->name, status, - slave->attached ? "attached" : "detached", - slave->enabled ? "enabled" : "disabled"); + ds_put_format(&ds, "\nslave: %s: %s %s\n", slave->name, status, + slave->attached ? "attached" : "detached"); ds_put_format(&ds, "\tport_id: %u\n", slave->port_id); ds_put_format(&ds, "\tport_priority: %u\n", slave->port_priority);