Looks good to me.  Only a few minor comments, and questions.  This
will really make it much easier to work on both the bridge and bonding
so I think it's a huge win.

Ethan

> +    /* Tag set saved for next bond_run(). */
> +    struct tag_set tags;
> +};

It wasn't entirely clear to me exactly what this tag set is for.  I
assume its a tag_set of slaves which need to be revalidated?  I think
it could benefit from a more descriptive name then tags if you have
one handy.


> +/* Frees 'bond'.@ */
> +void
> +bond_destroy(struct bond *bond)
> +{

Unnecessary @ in the comment.


> +    HMAP_FOR_EACH_SAFE (slave, next_slave, hmap_node, &bond->slaves) {
> +        hmap_remove(&bond->slaves, &slave->hmap_node);
> +        /* Client owns 'slave->netdev'. */
> +        free(slave->name);
> +        free(slave);
> +    }

I wonder if it would make sense for bond_destroy to return a tag union
of all the slaves which were removed.  This would allow the caller to
revalidate the relevant flows.


> +/* Callback for lacp_run(). */
> +static void
> +bond_send_pdu_cb(void *slave_, const struct lacp_pdu *pdu)
> +{
> +    struct bond_slave *slave = slave_;
> +    uint8_t ea[ETH_ADDR_LEN];
> +    int error;
> +
> +    error = netdev_get_etheraddr(slave->netdev, ea);
> +    if (!error) {
> +        struct lacp_pdu *packet_pdu;
> +        struct ofpbuf packet;
> +
> +        ofpbuf_init(&packet, 0);
> +        packet_pdu = eth_compose(&packet, eth_addr_lacp, ea, ETH_TYPE_LACP,
> +                                  sizeof *packet_pdu);

Incorrect indentation here.

> +    /* Enable slaves based on link status and LACP feedbkac. */
> +    HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
> +        bond_link_status_update(slave, tags);
> +    }

Typo in the comment.

> +    if (!tag_set_is_empty(&bond->tags)) {
> +        poll_immediate_wake();
> +    }

After some thinking I realized that this is so bond_run can cause its
tags to be revalidated immediately.  It looks slightly strange, so I
think it could benefit from a comment.

> +/* Returns true if 'bond' needs the client to send out packets to send out
> + * packets to assist with MAC learning on 'bond'.  If this function returns
> + * true, then the client should iterate through its MAC learning table for 
> the
> + * bridge on which 'bond' is located.  For each MAC that has been learned on 
> a
> + * port other than 'bond', it should call bond_send_learning_packet().
> + *
> + * This function will only return true if 'bond' is in SLB mode and LACP is 
> not
> + * negotiated.  Otherwise sending learning packets isn't necessary.
> + *
> + * Calling this function resets the state that it checks. */

Typo in the first sentence of this comment.

> +static struct bond_entry *
> +choose_entry_to_migrate(const struct bond_slave *from, uint64_t to_tx_bytes)
> +{
> +    struct bond_entry *e;
> +
> +    LIST_FOR_EACH (e, list_node, &from->entries) {
> +        double old_ratio, new_ratio;
> +        uint64_t delta = e->tx_bytes;
> +
> +        if (delta == 0 || from->tx_bytes - delta == 0) {
> +            /* Pointless move. */
> +            continue;
> +        }

I may have misinterpreted the code, but it seems to me that
from->tx_bytes should always be >= delta.  Is this correct?  It may be
worth asserting to avoid strange rebalancing decisions which are hard
to track down.

> +
> +        if (to_tx_bytes == 0) {
> +            /* Nothing on the new slave, move it. */
> +            return e;
> +        }
> +
> +        old_ratio = (double)from->tx_bytes / to_tx_bytes;
> +        new_ratio = (double)(from->tx_bytes - delta) /
> +            (to_tx_bytes + delta);
> +
> +        if (new_ratio == 0) {
> +            /* Should already be covered but check to prevent division
> +             * by zero. */
> +            continue;
> +        }
> +
> +        if (new_ratio < 1) {
> +            new_ratio = 1 / new_ratio;
> +        }

Assuming my previous assumption is correct, that from->tx_bytes is
always greater or equal to delta.  It's not clear to me how new_ration
could ever be > 1.  Do we need the check?  Perhaps an assertion would
be better?

> +static void
> +bond_unixctl_show(struct unixctl_conn *conn,
> +                  const char *args, void *aux OVS_UNUSED)
> +{
> +    struct ds ds = DS_EMPTY_INITIALIZER;
> +    const struct bond_slave *slave;
> +    const struct bond *bond;
> +
> +    bond = bond_find(args);
> +    if (!bond) {
> +        unixctl_command_reply(conn, 501, "no such bond");
> +        return;
> +    }
> +
> +    ds_put_format(&ds, "bond_mode: %s\n",
> +                  bond_mode_to_string(bond->balance));
> +
> +    if (bond->lacp) {
> +        ds_put_format(&ds, "lacp: %s\n",
> +                      lacp_is_active(bond->lacp) ? "active" : "passive");
> +    } else {
> +        ds_put_cstr(&ds, "lacp: off\n");
> +    }
> +
> +    if (bond->balance != BM_AB) {
> +        ds_put_format(&ds, "bond-hash-algorithm: %s\n",
> +                      bond_is_tcp_hash(bond) ? "balance-tcp" : 
> "balance-slb");
> +    }
> +
> +

Redundant newline.

> +
> +static void
> +enable_slave(struct unixctl_conn *conn, const char *args_, bool enable)
> +{
> +    char *args = (char *) args_;
> +    char *save_ptr = NULL;
> +    char *bond_s, *slave_s;
> +    struct bond *bond;
> +    struct bond_slave *slave;
> +
> +    bond_s = strtok_r(args, " ", &save_ptr);
> +    slave_s = strtok_r(NULL, " ", &save_ptr);
> +    if (!slave_s) {
> +        unixctl_command_reply(conn, 501,
> +                              "usage: bond/enable/disable-slave BOND SLAVE");

I think this would be clearer if we simply used a ternary operator to
print the command the user actually typed. "usage: bond/%s-slave BOND
SLAVE", enable ? "enable" : "disable"
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to