/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "ofpbuf.h"
#include "ofproto/ofproto-provider.h"
#include "ofproto/ofproto-dpif.h"
+#include "ofproto/ofproto-dpif-rid.h"
#include "connectivity.h"
#include "coverage.h"
#include "dynamic-string.h"
#include "odp-util.h"
#include "ofpbuf.h"
#include "packets.h"
+#include "dp-packet.h"
#include "poll-loop.h"
#include "seq.h"
#include "match.h"
#include "shash.h"
#include "timeval.h"
#include "unixctl.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(bond);
void *aux; /* Client-provided handle for this slave. */
struct netdev *netdev; /* Network device, owned by the client. */
- unsigned int change_seq; /* Tracks changes in 'netdev'. */
+ uint64_t change_seq; /* Tracks changes in 'netdev'. */
ofp_port_t ofp_port; /* OpenFlow port number. */
char *name; /* Name (a copy of netdev_get_name(netdev)). */
/* Interface name may not be persistent across an OS reboot, use
* MAC address for identifing the active slave */
- uint8_t active_slave_mac[ETH_ADDR_LEN];
+ struct eth_addr active_slave_mac;
/* The MAC address of the active interface. */
/* Legacy compatibility. */
bool lacp_fallback_ab; /* Fallback to active-backup on LACP failure. */
OVS_REQ_WRLOCK(rwlock);
static void bond_choose_active_slave(struct bond *)
OVS_REQ_WRLOCK(rwlock);
-static unsigned int bond_hash_src(const uint8_t mac[ETH_ADDR_LEN],
+static unsigned int bond_hash_src(const struct eth_addr mac,
uint16_t vlan, uint32_t basis);
static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan,
uint32_t basis);
hmap_destroy(&bond->pr_rule_ops);
if (bond->recirc_id) {
- ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id);
+ recirc_free_id(bond->recirc_id);
}
free(bond);
static void
update_recirc_rules(struct bond *bond)
+ OVS_REQ_WRLOCK(rwlock)
{
struct match match;
struct bond_pr_rule_op *pr_op, *next_op;
if (bond->balance != BM_AB) {
if (!bond->recirc_id) {
- bond->recirc_id = ofproto_dpif_alloc_recirc_id(bond->ofproto);
+ bond->recirc_id = recirc_alloc_id(bond->ofproto);
}
} else if (bond->recirc_id) {
- ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id);
+ recirc_free_id(bond->recirc_id);
bond->recirc_id = 0;
}
bond_entry_reset(bond);
}
- memcpy(bond->active_slave_mac, s->active_slave_mac,
- sizeof s->active_slave_mac);
-
+ bond->active_slave_mac = s->active_slave_mac;
bond->active_slave_changed = false;
ovs_rwlock_unlock(&rwlock);
}
static struct bond_slave *
-bond_find_slave_by_mac(const struct bond *bond, const uint8_t mac[ETH_ADDR_LEN])
+bond_find_slave_by_mac(const struct bond *bond, const struct eth_addr mac)
{
struct bond_slave *slave;
/* Find the last active slave */
HMAP_FOR_EACH(slave, hmap_node, &bond->slaves) {
- uint8_t slave_mac[ETH_ADDR_LEN];
+ struct eth_addr slave_mac;
- if (netdev_get_etheraddr(slave->netdev, slave_mac)) {
+ if (netdev_get_etheraddr(slave->netdev, &slave_mac)) {
continue;
}
- if (!memcmp(slave_mac, mac, sizeof(slave_mac))) {
+ if (eth_addr_equals(slave_mac, mac)) {
return slave;
}
}
static void
bond_active_slave_changed(struct bond *bond)
{
- uint8_t mac[ETH_ADDR_LEN];
+ struct eth_addr mac;
- netdev_get_etheraddr(bond->active_slave->netdev, mac);
- memcpy(bond->active_slave_mac, mac, sizeof bond->active_slave_mac);
+ netdev_get_etheraddr(bond->active_slave->netdev, &mac);
+ bond->active_slave_mac = mac;
bond->active_slave_changed = true;
seq_change(connectivity_seq_get());
}
* See bond_should_send_learning_packets() for description of usage. The
* caller should send the composed packet on the port associated with
* port_aux and takes ownership of the returned ofpbuf. */
-struct ofpbuf *
-bond_compose_learning_packet(struct bond *bond,
- const uint8_t eth_src[ETH_ADDR_LEN],
+struct dp_packet *
+bond_compose_learning_packet(struct bond *bond, const struct eth_addr eth_src,
uint16_t vlan, void **port_aux)
{
struct bond_slave *slave;
- struct ofpbuf *packet;
+ struct dp_packet *packet;
struct flow flow;
ovs_rwlock_rdlock(&rwlock);
ovs_assert(may_send_learning_packets(bond));
memset(&flow, 0, sizeof flow);
- memcpy(flow.dl_src, eth_src, ETH_ADDR_LEN);
+ flow.dl_src = eth_src;
slave = choose_output_slave(bond, &flow, NULL, vlan);
- packet = ofpbuf_new(0);
+ packet = dp_packet_new(0);
compose_rarp(packet, eth_src);
if (vlan) {
eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(vlan));
*/
enum bond_verdict
bond_check_admissibility(struct bond *bond, const void *slave_,
- const uint8_t eth_dst[ETH_ADDR_LEN])
+ const struct eth_addr eth_dst)
{
enum bond_verdict verdict = BV_DROP;
struct bond_slave *slave;
}
}
-void
-bond_update_post_recirc_rules(struct bond* bond, const bool force)
+static void
+bond_update_post_recirc_rules__(struct bond* bond, const bool force)
+ OVS_REQ_WRLOCK(rwlock)
{
struct bond_entry *e;
bool update_rules = force; /* Always update rules if caller forces it. */
update_recirc_rules(bond);
}
}
+
+void
+bond_update_post_recirc_rules(struct bond* bond, const bool force)
+{
+ ovs_rwlock_wrlock(&rwlock);
+ bond_update_post_recirc_rules__(bond, force);
+ ovs_rwlock_unlock(&rwlock);
+}
\f
/* Rebalancing. */
}
LIST_FOR_EACH (e, list_node, &from->entries) {
- double old_ratio, new_ratio;
- uint64_t delta;
-
- if (to_tx_bytes == 0) {
- /* Nothing on the new slave, move it. */
- return e;
- }
-
- delta = e->tx_bytes;
- old_ratio = (double)from->tx_bytes / to_tx_bytes;
- new_ratio = (double)(from->tx_bytes - delta) / (to_tx_bytes + delta);
- if (old_ratio - new_ratio > 0.1
- && fabs(new_ratio - 1.0) < fabs(old_ratio - 1.0)) {
- /* We're aiming for an ideal ratio of 1, meaning both the 'from'
- and 'to' slave have the same load. Therefore, we only move an
- entry if it decreases the load on 'from', and brings us closer
- to equal traffic load. */
+ uint64_t delta = e->tx_bytes; /* The amount to rebalance. */
+ uint64_t ideal_tx_bytes = (from->tx_bytes + to_tx_bytes)/2;
+ /* Note, the ideal traffic is the mid point
+ * between 'from' and 'to'. This value does
+ * not change by rebalancing. */
+ uint64_t new_low; /* The lower bandwidth between 'to' and 'from'
+ after rebalancing. */
+
+ new_low = MIN(from->tx_bytes - delta, to_tx_bytes + delta);
+
+ if ((new_low > to_tx_bytes) &&
+ (new_low - to_tx_bytes >= (ideal_tx_bytes - to_tx_bytes) / 10)) {
+ /* Only rebalance if the new 'low' is closer to to the mid point,
+ * and the improvement exceeds 10% of current traffic
+ * deviation from the ideal split.
+ *
+ * The improvement on the 'high' side is always the same as the
+ * 'low' side. Thus consider 'low' side is sufficient. */
return e;
}
}
}
bond->next_rebalance = time_msec() + bond->rebalance_interval;
- use_recirc = ofproto_dpif_get_enable_recirc(bond->ofproto) &&
+ use_recirc = ofproto_dpif_get_support(bond->ofproto)->odp.recirc &&
bond_may_recirc(bond, NULL, NULL);
if (use_recirc) {
}
if (use_recirc && rebalanced) {
- bond_update_post_recirc_rules(bond,true);
+ bond_update_post_recirc_rules__(bond,true);
}
done:
const char *mac_s = argv[1];
const char *vlan_s = argc > 2 ? argv[2] : NULL;
const char *basis_s = argc > 3 ? argv[3] : NULL;
- uint8_t mac[ETH_ADDR_LEN];
+ struct eth_addr mac;
uint8_t hash;
char *hash_cstr;
unsigned int vlan;
}
static unsigned int
-bond_hash_src(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan, uint32_t basis)
+bond_hash_src(const struct eth_addr mac, uint16_t vlan, uint32_t basis)
{
return hash_mac(mac, vlan, basis);
}
* If return true, 'mac' will store the bond's current active slave's
* MAC address. */
bool
-bond_get_changed_active_slave(const char *name, uint8_t* mac, bool force)
+bond_get_changed_active_slave(const char *name, struct eth_addr *mac,
+ bool force)
{
struct bond *bond;
bond = bond_find(name);
if (bond) {
if (bond->active_slave_changed || force) {
- memcpy(mac, bond->active_slave_mac, ETH_ADDR_LEN);
+ *mac = bond->active_slave_mac;
bond->active_slave_changed = false;
ovs_rwlock_unlock(&rwlock);
return true;