X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Flacp.c;h=a7f66a24ab0c2e8e1f282c49c6f77a341238f61f;hb=b0387df4e0ac796af05765834bb6e7750b8b6ae6;hp=3c7b1caab5a13dc1d417c4f7259527b42b919397;hpb=206018136a10d00b275d85386c5744a555584151;p=openvswitch diff --git a/lib/lacp.c b/lib/lacp.c index 3c7b1caa..a7f66a24 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -48,7 +48,8 @@ struct lacp { struct hmap slaves; /* Slaves this LACP object controls. */ struct slave *key_slave; /* Slave whose ID will be the aggregation key. */ - bool fast; /* Fast or Slow LACP time. */ + 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. */ @@ -87,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) @@ -143,7 +189,8 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s) } lacp->active = s->active; - lacp->fast = s->fast; + 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 @@ -162,11 +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; - timer_set_duration(&slave->rx, (lacp->fast - ? LACP_FAST_TIME_RX - : LACP_SLOW_TIME_RX)); + timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * tx_rate); slave->ntt_actor = pdu->partner; @@ -319,15 +378,21 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) 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); - timer_set_duration(&slave->tx, - (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); } } } @@ -443,10 +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; - timer_set_duration(&slave->rx, 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 @@ -458,7 +531,7 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor) state |= LACP_STATE_ACT; } - if (slave->lacp->fast) { + if (slave->lacp->lacp_time != LACP_TIME_SLOW) { state |= LACP_STATE_TIME; } @@ -647,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;