mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
Eliminate use of term "slave" in bond, LACP, and bundle contexts.
The new term is "member". Most of these changes should not change user-visible behavior. One place where they do is in "ovs-ofctl dump-flows", which will now output "members:..." inside "bundle" actions instead of "slaves:...". I don't expect this to cause real problems in most systems. The old syntax is still supported on input for backward compatibility. Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com>
This commit is contained in:
parent
f51cf36d86
commit
91fc374a9c
@ -25,22 +25,22 @@
|
||||
Bonding
|
||||
=======
|
||||
|
||||
Bonding allows two or more interfaces (the "slaves") to share network traffic.
|
||||
Bonding allows two or more interfaces, its "members", to share network traffic.
|
||||
From a high-level point of view, bonded interfaces act like a single port, but
|
||||
they have the bandwidth of multiple network devices, e.g. two 1 GB physical
|
||||
interfaces act like a single 2 GB interface. Bonds also increase robustness:
|
||||
the bonded port does not go down as long as at least one of its slaves is up.
|
||||
the bonded port does not go down as long as at least one of its members is up.
|
||||
|
||||
In vswitchd, a bond always has at least two slaves (and may have more). If a
|
||||
configuration error, etc. would cause a bond to have only one slave, the port
|
||||
In vswitchd, a bond always has at least two members (and may have more). If a
|
||||
configuration error, etc. would cause a bond to have only one member, the port
|
||||
becomes an ordinary port, not a bonded port, and none of the special features
|
||||
of bonded ports described in this section apply.
|
||||
|
||||
There are many forms of bonding of which ovs-vswitchd implements only a few.
|
||||
The most complex bond ovs-vswitchd implements is called "source load balancing"
|
||||
or SLB bonding. SLB bonding divides traffic among the slaves based on the
|
||||
Ethernet source address. This is useful only if the traffic over the bond has
|
||||
multiple Ethernet source addresses, for example if network traffic from
|
||||
or SLB bonding. SLB bonding divides traffic among the members based on
|
||||
the Ethernet source address. This is useful only if the traffic over the bond
|
||||
has multiple Ethernet source addresses, for example if network traffic from
|
||||
multiple VMs are multiplexed over the bond.
|
||||
|
||||
.. note::
|
||||
@ -50,89 +50,90 @@ multiple VMs are multiplexed over the bond.
|
||||
specified.
|
||||
|
||||
|
||||
Enabling and Disabling Slaves
|
||||
-----------------------------
|
||||
Enabling and Disabling Members
|
||||
------------------------------
|
||||
|
||||
When a bond is created, a slave is initially enabled or disabled based on
|
||||
whether carrier is detected on the NIC (see ``iface_create()``). After that, a
|
||||
slave is disabled if its carrier goes down for a period of time longer than the
|
||||
downdelay, and it is enabled if carrier comes up for longer than the updelay
|
||||
(see ``bond_link_status_update()``). There is one exception where the updelay
|
||||
is skipped: if no slaves at all are currently enabled, then the first slave on
|
||||
which carrier comes up is enabled immediately.
|
||||
When a bond is created, a member is initially enabled or disabled based
|
||||
on whether carrier is detected on the NIC (see ``iface_create()``). After
|
||||
that, a member is disabled if its carrier goes down for a period of time
|
||||
longer than the downdelay, and it is enabled if carrier comes up for longer
|
||||
than the updelay (see ``bond_link_status_update()``). There is one exception
|
||||
where the updelay is skipped: if no members at all are currently
|
||||
enabled, then the first member on which carrier comes up is enabled
|
||||
immediately.
|
||||
|
||||
The updelay should be set to a time longer than the STP forwarding delay of the
|
||||
physical switch to which the bond port is connected (if STP is enabled on that
|
||||
switch). Otherwise, the slave will be enabled, and load may be shifted to it,
|
||||
before the physical switch starts forwarding packets on that port, which can
|
||||
cause some data to be "blackholed" for a time. The exception for a single
|
||||
enabled slave does not cause any problem in this regard because when no slaves
|
||||
are enabled all output packets are blackholed anyway.
|
||||
switch). Otherwise, the member will be enabled, and load may be shifted
|
||||
to it, before the physical switch starts forwarding packets on that port, which
|
||||
can cause some data to be dropped for a time. The exception for a single
|
||||
enabled member does not cause any problem in this regard because when no
|
||||
members are enabled all output packets are dropped anyway.
|
||||
|
||||
When a slave becomes disabled, the vswitch immediately chooses a new output
|
||||
port for traffic that was destined for that slave (see
|
||||
``bond_enable_slave()``). It also sends a "gratuitous learning packet",
|
||||
specifically a RARP, on the bond port (on the newly chosen slave) for each MAC
|
||||
address that the vswitch has learned on a port other than the bond (see
|
||||
``bundle_send_learning_packets()``), to teach the physical switch that the new
|
||||
slave should be used in place of the one that is now disabled. (This behavior
|
||||
probably makes sense only for a vswitch that has only one port (the bond)
|
||||
connected to a physical switch; vswitchd should probably provide a way to
|
||||
disable or configure it in other scenarios.)
|
||||
When a member becomes disabled, the vswitch immediately chooses a new
|
||||
output port for traffic that was destined for that member (see
|
||||
``bond_enable_member()``). It also sends a "gratuitous learning packet",
|
||||
specifically a RARP, on the bond port (on the newly chosen member) for
|
||||
each MAC address that the vswitch has learned on a port other than the bond
|
||||
(see ``bundle_send_learning_packets()``), to teach the physical switch that the
|
||||
new member should be used in place of the one that is now disabled.
|
||||
(This behavior probably makes sense only for a vswitch that has only one port
|
||||
(the bond) connected to a physical switch; vswitchd should probably provide a
|
||||
way to disable or configure it in other scenarios.)
|
||||
|
||||
Bond Packet Input
|
||||
-----------------
|
||||
|
||||
Bonding accepts unicast packets on any bond slave. This can occasionally cause
|
||||
packet duplication for the first few packets sent to a given MAC, if the
|
||||
Bonding accepts unicast packets on any member. This can occasionally
|
||||
cause packet duplication for the first few packets sent to a given MAC, if the
|
||||
physical switch attached to the bond is flooding packets to that MAC because it
|
||||
has not yet learned the correct slave for that MAC.
|
||||
has not yet learned the correct member for that MAC.
|
||||
|
||||
Bonding only accepts multicast (and broadcast) packets on a single bond slave
|
||||
(the "active slave") at any given time. Multicast packets received on other
|
||||
slaves are dropped. Otherwise, every multicast packet would be duplicated,
|
||||
once for every bond slave, because the physical switch attached to the bond
|
||||
will flood those packets.
|
||||
Bonding only accepts multicast (and broadcast) packets on a single bond
|
||||
member (the "active member") at any given time. Multicast
|
||||
packets received on other members are dropped. Otherwise, every
|
||||
multicast packet would be duplicated, once for every bond member,
|
||||
because the physical switch attached to the bond will flood those packets.
|
||||
|
||||
Bonding also drops received packets when the vswitch has learned that the
|
||||
packet's MAC is on a port other than the bond port itself. This is because it
|
||||
is likely that the vswitch itself sent the packet out the bond port on a
|
||||
different slave and is now receiving the packet back. This occurs when the
|
||||
packet is multicast or the physical switch has not yet learned the MAC and is
|
||||
flooding it. However, the vswitch makes an exception to this rule for
|
||||
different member and is now receiving the packet back. This occurs when
|
||||
the packet is multicast or the physical switch has not yet learned the MAC and
|
||||
is flooding it. However, the vswitch makes an exception to this rule for
|
||||
broadcast ARP replies, which indicate that the MAC has moved to another switch,
|
||||
probably due to VM migration. (ARP replies are normally unicast, so this
|
||||
exception does not match normal ARP replies. It will match the learning
|
||||
packets sent on bond fail-over.)
|
||||
|
||||
The active slave is simply the first slave to be enabled after the bond is
|
||||
created (see ``bond_choose_active_slave()``). If the active slave is disabled,
|
||||
then a new active slave is chosen among the slaves that remain active.
|
||||
Currently due to the way that configuration works, this tends to be the
|
||||
remaining slave whose interface name is first alphabetically, but this is by no
|
||||
means guaranteed.
|
||||
The active member is simply the first member to be enabled after
|
||||
the bond is created (see ``bond_choose_active_member()``). If the active
|
||||
member is disabled, then a new active member is chosen among the
|
||||
members that remain active. Currently due to the way that configuration
|
||||
works, this tends to be the remaining member whose interface name is
|
||||
first alphabetically, but this is by no means guaranteed.
|
||||
|
||||
Bond Packet Output
|
||||
------------------
|
||||
|
||||
When a packet is sent out a bond port, the bond slave actually used is selected
|
||||
based on the packet's source MAC and VLAN tag (see ``bond_choose_output_slave()``).
|
||||
In particular, the source MAC and VLAN tag are hashed into one of 256 values,
|
||||
and that value is looked up in a hash table (the "bond hash") kept in the
|
||||
``bond_hash`` member of struct port. The hash table entry identifies a bond
|
||||
slave. If no bond slave has yet been chosen for that hash table entry,
|
||||
vswitchd chooses one arbitrarily.
|
||||
When a packet is sent out a bond port, the bond member actually used is
|
||||
selected based on the packet's source MAC and VLAN tag (see
|
||||
``bond_choose_output_member()``). In particular, the source MAC and VLAN tag
|
||||
are hashed into one of 256 values, and that value is looked up in a hash table
|
||||
(the "bond hash") kept in the ``bond_hash`` member of struct port. The hash
|
||||
table entry identifies a bond member. If no bond member has yet been chosen
|
||||
for that hash table entry, vswitchd chooses one arbitrarily.
|
||||
|
||||
Every 10 seconds, vswitchd rebalances the bond slaves (see
|
||||
``bond_rebalance()``). To rebalance, vswitchd examines the statistics for
|
||||
the number of bytes transmitted by each slave over approximately the past
|
||||
Every 10 seconds, vswitchd rebalances the bond members (see
|
||||
``bond_rebalance()``). To rebalance, vswitchd examines the statistics for the
|
||||
number of bytes transmitted by each member over approximately the past
|
||||
minute, with data sent more recently weighted more heavily than data sent less
|
||||
recently. It considers each of the slaves in order from most-loaded to
|
||||
least-loaded. If highly loaded slave H is significantly more heavily loaded
|
||||
than the least-loaded slave L, and slave H carries at least two hashes, then
|
||||
vswitchd shifts one of H's hashes to L. However, vswitchd will only shift a
|
||||
hash from H to L if it will decrease the ratio of the load between H and L by
|
||||
at least 0.1.
|
||||
recently. It considers each of the members in order from most-loaded to
|
||||
least-loaded. If highly loaded member H is significantly more heavily
|
||||
loaded than the least-loaded member L, and member H carries at
|
||||
least two hashes, then vswitchd shifts one of H's hashes to L. However,
|
||||
vswitchd will only shift a hash from H to L if it will decrease the ratio of
|
||||
the load between H and L by at least 0.1.
|
||||
|
||||
Currently, "significantly more loaded" means that H must carry at least 1 Mbps
|
||||
more traffic, and that traffic must be at least 3% greater than L's.
|
||||
@ -166,11 +167,11 @@ behavior on Open vSwitch.
|
||||
Active Backup Bonding
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Active Backup bonds send all traffic out one "active" slave until that slave
|
||||
becomes unavailable. Since they are significantly less complicated than SLB
|
||||
bonds, they are preferred when LACP is not an option. Additionally, they are
|
||||
the only bond mode which supports attaching each slave to a different upstream
|
||||
switch.
|
||||
Active Backup bonds send all traffic out one "active" member until that
|
||||
member becomes unavailable. Since they are significantly less
|
||||
complicated than SLB bonds, they are preferred when LACP is not an option.
|
||||
Additionally, they are the only bond mode which supports attaching each
|
||||
member to a different upstream switch.
|
||||
|
||||
SLB Bonding
|
||||
~~~~~~~~~~~
|
||||
@ -195,15 +196,15 @@ SLB bonding has the following complications:
|
||||
This would cause packet duplication if not handled specially.
|
||||
|
||||
Open vSwitch avoids packet duplication by accepting multicast and broadcast
|
||||
packets on only the active slave, and dropping multicast and broadcast
|
||||
packets on all other slaves.
|
||||
packets on only the active member, and dropping multicast and
|
||||
broadcast packets on all other members.
|
||||
|
||||
2. When Open vSwitch forwards a multicast or broadcast packet to a link in the
|
||||
SLB bond other than the active slave, the remote switch will forward it to
|
||||
all of the other links in the SLB bond, including the active slave. Without
|
||||
special handling, this would mean that Open vSwitch would forward a second
|
||||
copy of the packet to each switch port (other than the bond), including the
|
||||
port that originated the packet.
|
||||
SLB bond other than the active member, the remote switch will forward
|
||||
it to all of the other links in the SLB bond, including the active
|
||||
member. Without special handling, this would mean that Open vSwitch
|
||||
would forward a second copy of the packet to each switch port (other than
|
||||
the bond), including the port that originated the packet.
|
||||
|
||||
Open vSwitch deals with this case by dropping packets received on any SLB
|
||||
bonded link that have a source MAC+VLAN that has been learned on any other
|
||||
@ -226,11 +227,11 @@ SLB bonding has the following complications:
|
||||
4. Suppose that a MAC+VLAN moves from an SLB bond to another port (e.g. when a
|
||||
VM is migrated from a different hypervisor to this one), that the MAC+VLAN
|
||||
emits a gratuitous ARP, and that Open vSwitch forwards that gratuitous ARP
|
||||
to a link in the SLB bond other than the active slave. The remote switch
|
||||
will forward the gratuitous ARP to all of the other links in the SLB bond,
|
||||
including the active slave. Without additional special handling, this would
|
||||
mean that Open vSwitch would learn that the MAC+VLAN was located on the SLB
|
||||
bond, as a consequence of rule #3.
|
||||
to a link in the SLB bond other than the active member. The remote
|
||||
switch will forward the gratuitous ARP to all of the other links in the SLB
|
||||
bond, including the active member. Without additional special
|
||||
handling, this would mean that Open vSwitch would learn that the MAC+VLAN
|
||||
was located on the SLB bond, as a consequence of rule #3.
|
||||
|
||||
Open vSwitch avoids this problem by "locking" the MAC learning table entry
|
||||
for a MAC+VLAN from which a gratuitous ARP was received from a non-SLB bond
|
||||
|
@ -42,8 +42,8 @@ concordance, indexed by the area of the source tree:
|
||||
datapath/ vport ---
|
||||
vswitchd/ iface port
|
||||
ofproto/ port bundle
|
||||
ofproto/bond.c slave bond
|
||||
lib/lacp.c slave lacp
|
||||
ofproto/bond.c member bond
|
||||
lib/lacp.c member lacp
|
||||
lib/netdev.c netdev ---
|
||||
database Interface Port
|
||||
|
||||
|
4
NEWS
4
NEWS
@ -12,6 +12,8 @@ Post-v2.14.0
|
||||
- Terminology:
|
||||
* The terms "master" and "slave" have been replaced by "primary" and
|
||||
"secondary", respectively, for OpenFlow connection roles.
|
||||
* The term "slave" has been replaced by "member", for bonds, LACP, and
|
||||
OpenFlow bundle actions.
|
||||
|
||||
|
||||
v2.14.0 - 17 Aug 2020
|
||||
@ -833,7 +835,7 @@ v2.4.0 - 20 Aug 2015
|
||||
The implementation has been tested successfully against the Ixia Automated
|
||||
Network Validation Library (ANVL).
|
||||
- Stats are no longer updated on fake bond interface.
|
||||
- Keep active bond slave selection across OVS restart.
|
||||
- Keep active bond interface selection across OVS restart.
|
||||
- A simple wrapper script, 'ovs-docker', to integrate OVS with Docker
|
||||
containers. If and when there is a native integration of Open vSwitch
|
||||
with Docker, the wrapper script will be retired.
|
||||
|
2
debian/changelog
vendored
2
debian/changelog
vendored
@ -388,7 +388,7 @@ openvswitch (2.4.0-1) unstable; urgency=low
|
||||
The implementation has been tested successfully against the Ixia Automated
|
||||
Network Validation Library (ANVL).
|
||||
- Stats are no longer updated on fake bond interface.
|
||||
- Keep active bond slave selection across OVS restart.
|
||||
- Keep active bond member selection across OVS restart.
|
||||
- A simple wrapper script, 'ovs-docker', to integrate OVS with Docker
|
||||
containers. If and when there is a native integration of Open vSwitch
|
||||
with Docker, the wrapper script will be retired.
|
||||
|
4
debian/ifupdown.sh
vendored
4
debian/ifupdown.sh
vendored
@ -65,9 +65,9 @@ if [ "${MODE}" = "start" ]; then
|
||||
${OVS_EXTRA+-- $OVS_EXTRA}
|
||||
|
||||
ip link set "${IFACE}" up
|
||||
for slave in ${IF_OVS_BONDS}
|
||||
for member in ${IF_OVS_BONDS}
|
||||
do
|
||||
ip link set "${slave}" up
|
||||
ip link set "${member}" up
|
||||
done
|
||||
;;
|
||||
OVSPatchPort)
|
||||
|
@ -66,7 +66,7 @@ struct vl_mff_map;
|
||||
OFPACT(CONTROLLER, ofpact_controller, userdata, "controller") \
|
||||
OFPACT(ENQUEUE, ofpact_enqueue, ofpact, "enqueue") \
|
||||
OFPACT(OUTPUT_REG, ofpact_output_reg, ofpact, "output_reg") \
|
||||
OFPACT(BUNDLE, ofpact_bundle, slaves, "bundle") \
|
||||
OFPACT(BUNDLE, ofpact_bundle, members, "bundle") \
|
||||
\
|
||||
/* Header changes. */ \
|
||||
OFPACT(SET_FIELD, ofpact_set_field, ofpact, "set_field") \
|
||||
@ -364,24 +364,24 @@ struct ofpact_output_trunc {
|
||||
);
|
||||
};
|
||||
|
||||
/* Bundle slave choice algorithm to apply.
|
||||
/* Bundle member choice algorithm to apply.
|
||||
*
|
||||
* In the descriptions below, 'slaves' is the list of possible slaves in the
|
||||
* In the descriptions below, 'members' is the list of possible members in the
|
||||
* order they appear in the OpenFlow action. */
|
||||
enum nx_bd_algorithm {
|
||||
/* Chooses the first live slave listed in the bundle.
|
||||
/* Chooses the first live member listed in the bundle.
|
||||
*
|
||||
* O(n_slaves) performance. */
|
||||
* O(n_members) performance. */
|
||||
NX_BD_ALG_ACTIVE_BACKUP = 0,
|
||||
|
||||
/* Highest Random Weight.
|
||||
*
|
||||
* for i in [0,n_slaves):
|
||||
* for i in [0,n_members):
|
||||
* weights[i] = hash(flow, i)
|
||||
* slave = { slaves[i] such that weights[i] >= weights[j] for all j != i }
|
||||
* member = { members[i] such that weights[i] >= weights[j] for all j != i }
|
||||
*
|
||||
* Redistributes 1/n_slaves of traffic when a slave's liveness changes.
|
||||
* O(n_slaves) performance.
|
||||
* Redistributes 1/n_members of traffic when a member's liveness changes.
|
||||
* O(n_members) performance.
|
||||
*
|
||||
* Uses the 'fields' and 'basis' parameters. */
|
||||
NX_BD_ALG_HRW = 1
|
||||
@ -394,7 +394,7 @@ struct ofpact_bundle {
|
||||
OFPACT_PADDED_MEMBERS(
|
||||
struct ofpact ofpact;
|
||||
|
||||
/* Slave choice algorithm to apply to hash value. */
|
||||
/* Member choice algorithm to apply to hash value. */
|
||||
enum nx_bd_algorithm algorithm;
|
||||
|
||||
/* What fields to hash and how. */
|
||||
@ -403,10 +403,12 @@ struct ofpact_bundle {
|
||||
|
||||
struct mf_subfield dst;
|
||||
|
||||
/* Slaves for output. */
|
||||
unsigned int n_slaves;
|
||||
bool compat_syntax;
|
||||
|
||||
/* Members for output. */
|
||||
unsigned int n_members;
|
||||
);
|
||||
ofp_port_t slaves[];
|
||||
ofp_port_t members[];
|
||||
};
|
||||
|
||||
/* OFPACT_SET_VLAN_VID.
|
||||
|
101
lib/bundle.c
101
lib/bundle.c
@ -39,14 +39,14 @@ VLOG_DEFINE_THIS_MODULE(bundle);
|
||||
|
||||
static ofp_port_t
|
||||
execute_ab(const struct ofpact_bundle *bundle,
|
||||
bool (*slave_enabled)(ofp_port_t ofp_port, void *aux), void *aux)
|
||||
bool (*member_enabled)(ofp_port_t ofp_port, void *aux), void *aux)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < bundle->n_slaves; i++) {
|
||||
ofp_port_t slave = bundle->slaves[i];
|
||||
if (slave_enabled(slave, aux)) {
|
||||
return slave;
|
||||
for (i = 0; i < bundle->n_members; i++) {
|
||||
ofp_port_t member = bundle->members[i];
|
||||
if (member_enabled(member, aux)) {
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,12 +56,12 @@ execute_ab(const struct ofpact_bundle *bundle,
|
||||
static ofp_port_t
|
||||
execute_hrw(const struct ofpact_bundle *bundle,
|
||||
const struct flow *flow, struct flow_wildcards *wc,
|
||||
bool (*slave_enabled)(ofp_port_t ofp_port, void *aux), void *aux)
|
||||
bool (*member_enabled)(ofp_port_t ofp_port, void *aux), void *aux)
|
||||
{
|
||||
uint32_t flow_hash, best_hash;
|
||||
int best, i;
|
||||
|
||||
if (bundle->n_slaves > 1) {
|
||||
if (bundle->n_members > 1) {
|
||||
flow_mask_hash_fields(flow, wc, bundle->fields);
|
||||
}
|
||||
|
||||
@ -69,8 +69,8 @@ execute_hrw(const struct ofpact_bundle *bundle,
|
||||
best = -1;
|
||||
best_hash = 0;
|
||||
|
||||
for (i = 0; i < bundle->n_slaves; i++) {
|
||||
if (slave_enabled(bundle->slaves[i], aux)) {
|
||||
for (i = 0; i < bundle->n_members; i++) {
|
||||
if (member_enabled(bundle->members[i], aux)) {
|
||||
uint32_t hash = hash_2words(i, flow_hash);
|
||||
|
||||
if (best < 0 || hash > best_hash) {
|
||||
@ -80,25 +80,25 @@ execute_hrw(const struct ofpact_bundle *bundle,
|
||||
}
|
||||
}
|
||||
|
||||
return best >= 0 ? bundle->slaves[best] : OFPP_NONE;
|
||||
return best >= 0 ? bundle->members[best] : OFPP_NONE;
|
||||
}
|
||||
|
||||
/* Executes 'bundle' on 'flow'. Sets fields in 'wc' that were used to
|
||||
* calculate the result. Uses 'slave_enabled' to determine if the slave
|
||||
* designated by 'ofp_port' is up. Returns the chosen slave, or
|
||||
* OFPP_NONE if none of the slaves are acceptable. */
|
||||
* calculate the result. Uses 'member_enabled' to determine if the member
|
||||
* designated by 'ofp_port' is up. Returns the chosen member, or
|
||||
* OFPP_NONE if none of the members are acceptable. */
|
||||
ofp_port_t
|
||||
bundle_execute(const struct ofpact_bundle *bundle,
|
||||
const struct flow *flow, struct flow_wildcards *wc,
|
||||
bool (*slave_enabled)(ofp_port_t ofp_port, void *aux),
|
||||
bool (*member_enabled)(ofp_port_t ofp_port, void *aux),
|
||||
void *aux)
|
||||
{
|
||||
switch (bundle->algorithm) {
|
||||
case NX_BD_ALG_HRW:
|
||||
return execute_hrw(bundle, flow, wc, slave_enabled, aux);
|
||||
return execute_hrw(bundle, flow, wc, member_enabled, aux);
|
||||
|
||||
case NX_BD_ALG_ACTIVE_BACKUP:
|
||||
return execute_ab(bundle, slave_enabled, aux);
|
||||
return execute_ab(bundle, member_enabled, aux);
|
||||
|
||||
default:
|
||||
OVS_NOT_REACHED();
|
||||
@ -119,21 +119,21 @@ bundle_check(const struct ofpact_bundle *bundle, ofp_port_t max_ports,
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < bundle->n_slaves; i++) {
|
||||
ofp_port_t ofp_port = bundle->slaves[i];
|
||||
for (i = 0; i < bundle->n_members; i++) {
|
||||
ofp_port_t ofp_port = bundle->members[i];
|
||||
|
||||
if (ofp_port != OFPP_NONE) {
|
||||
enum ofperr error = ofpact_check_output_port(ofp_port, max_ports);
|
||||
if (error) {
|
||||
VLOG_WARN_RL(&rl, "invalid slave %"PRIu32, ofp_port);
|
||||
VLOG_WARN_RL(&rl, "invalid member %"PRIu32, ofp_port);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
/* Controller slaves are unsupported due to the lack of a max_len
|
||||
/* Controller members are unsupported due to the lack of a max_len
|
||||
* argument. This may or may not change in the future. There doesn't
|
||||
* seem to be a real-world use-case for supporting it. */
|
||||
if (ofp_port == OFPP_CONTROLLER) {
|
||||
VLOG_WARN_RL(&rl, "unsupported controller slave");
|
||||
VLOG_WARN_RL(&rl, "unsupported controller member");
|
||||
return OFPERR_OFPBAC_BAD_OUT_PORT;
|
||||
}
|
||||
}
|
||||
@ -150,38 +150,39 @@ static char * OVS_WARN_UNUSED_RESULT
|
||||
bundle_parse__(const char *s, const struct ofputil_port_map *port_map,
|
||||
char **save_ptr,
|
||||
const char *fields, const char *basis, const char *algorithm,
|
||||
const char *slave_type, const char *dst,
|
||||
const char *slave_delim, struct ofpbuf *ofpacts)
|
||||
const char *member_type, const char *dst,
|
||||
const char *member_delim, struct ofpbuf *ofpacts)
|
||||
{
|
||||
struct ofpact_bundle *bundle;
|
||||
|
||||
if (!slave_delim) {
|
||||
if (!member_delim) {
|
||||
return xasprintf("%s: not enough arguments to bundle action", s);
|
||||
}
|
||||
|
||||
if (strcasecmp(slave_delim, "slaves")) {
|
||||
return xasprintf("%s: missing slave delimiter, expected `slaves' "
|
||||
"got `%s'", s, slave_delim);
|
||||
if (strcasecmp(member_delim, "members")
|
||||
&& strcasecmp(member_delim, "slaves")) {
|
||||
return xasprintf("%s: missing member delimiter, expected `members', "
|
||||
"got `%s'", s, member_delim);
|
||||
}
|
||||
|
||||
bundle = ofpact_put_BUNDLE(ofpacts);
|
||||
|
||||
for (;;) {
|
||||
ofp_port_t slave_port;
|
||||
char *slave;
|
||||
ofp_port_t member_port;
|
||||
char *member;
|
||||
|
||||
slave = strtok_r(NULL, ", []", save_ptr);
|
||||
if (!slave || bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
|
||||
member = strtok_r(NULL, ", []", save_ptr);
|
||||
if (!member || bundle->n_members >= BUNDLE_MAX_MEMBERS) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ofputil_port_from_string(slave, port_map, &slave_port)) {
|
||||
return xasprintf("%s: bad port number", slave);
|
||||
if (!ofputil_port_from_string(member, port_map, &member_port)) {
|
||||
return xasprintf("%s: bad port number", member);
|
||||
}
|
||||
ofpbuf_put(ofpacts, &slave_port, sizeof slave_port);
|
||||
ofpbuf_put(ofpacts, &member_port, sizeof member_port);
|
||||
|
||||
bundle = ofpacts->header;
|
||||
bundle->n_slaves++;
|
||||
bundle->n_members++;
|
||||
}
|
||||
|
||||
if (ofpbuf_oversized(ofpacts)) {
|
||||
@ -217,8 +218,8 @@ bundle_parse__(const char *s, const struct ofputil_port_map *port_map,
|
||||
return xasprintf("%s: unknown algorithm `%s'", s, algorithm);
|
||||
}
|
||||
|
||||
if (strcasecmp(slave_type, "ofport")) {
|
||||
return xasprintf("%s: unknown slave_type `%s'", s, slave_type);
|
||||
if (strcasecmp(member_type, "ofport")) {
|
||||
return xasprintf("%s: unknown member_type `%s'", s, member_type);
|
||||
}
|
||||
|
||||
if (dst) {
|
||||
@ -245,7 +246,7 @@ char * OVS_WARN_UNUSED_RESULT
|
||||
bundle_parse(const char *s, const struct ofputil_port_map *port_map,
|
||||
struct ofpbuf *ofpacts)
|
||||
{
|
||||
char *fields, *basis, *algorithm, *slave_type, *slave_delim;
|
||||
char *fields, *basis, *algorithm, *member_type, *member_delim;
|
||||
char *tokstr, *save_ptr;
|
||||
char *error;
|
||||
|
||||
@ -254,12 +255,12 @@ bundle_parse(const char *s, const struct ofputil_port_map *port_map,
|
||||
fields = strtok_r(tokstr, ", ", &save_ptr);
|
||||
basis = strtok_r(NULL, ", ", &save_ptr);
|
||||
algorithm = strtok_r(NULL, ", ", &save_ptr);
|
||||
slave_type = strtok_r(NULL, ", ", &save_ptr);
|
||||
slave_delim = strtok_r(NULL, ": ", &save_ptr);
|
||||
member_type = strtok_r(NULL, ", ", &save_ptr);
|
||||
member_delim = strtok_r(NULL, ": ", &save_ptr);
|
||||
|
||||
error = bundle_parse__(s, port_map,
|
||||
&save_ptr, fields, basis, algorithm, slave_type,
|
||||
NULL, slave_delim, ofpacts);
|
||||
&save_ptr, fields, basis, algorithm, member_type,
|
||||
NULL, member_delim, ofpacts);
|
||||
free(tokstr);
|
||||
|
||||
return error;
|
||||
@ -274,7 +275,7 @@ char * OVS_WARN_UNUSED_RESULT
|
||||
bundle_parse_load(const char *s, const struct ofputil_port_map *port_map,
|
||||
struct ofpbuf *ofpacts)
|
||||
{
|
||||
char *fields, *basis, *algorithm, *slave_type, *dst, *slave_delim;
|
||||
char *fields, *basis, *algorithm, *member_type, *dst, *member_delim;
|
||||
char *tokstr, *save_ptr;
|
||||
char *error;
|
||||
|
||||
@ -283,13 +284,13 @@ bundle_parse_load(const char *s, const struct ofputil_port_map *port_map,
|
||||
fields = strtok_r(tokstr, ", ", &save_ptr);
|
||||
basis = strtok_r(NULL, ", ", &save_ptr);
|
||||
algorithm = strtok_r(NULL, ", ", &save_ptr);
|
||||
slave_type = strtok_r(NULL, ", ", &save_ptr);
|
||||
member_type = strtok_r(NULL, ", ", &save_ptr);
|
||||
dst = strtok_r(NULL, ", ", &save_ptr);
|
||||
slave_delim = strtok_r(NULL, ": ", &save_ptr);
|
||||
member_delim = strtok_r(NULL, ": ", &save_ptr);
|
||||
|
||||
error = bundle_parse__(s, port_map,
|
||||
&save_ptr, fields, basis, algorithm, slave_type,
|
||||
dst, slave_delim, ofpacts);
|
||||
&save_ptr, fields, basis, algorithm, member_type,
|
||||
dst, member_delim, ofpacts);
|
||||
|
||||
free(tokstr);
|
||||
|
||||
@ -328,13 +329,13 @@ bundle_format(const struct ofpact_bundle *bundle,
|
||||
ds_put_char(s, ',');
|
||||
}
|
||||
|
||||
ds_put_format(s, "%sslaves:%s", colors.param, colors.end);
|
||||
for (i = 0; i < bundle->n_slaves; i++) {
|
||||
ds_put_format(s, "%smembers:%s", colors.param, colors.end);
|
||||
for (i = 0; i < bundle->n_members; i++) {
|
||||
if (i) {
|
||||
ds_put_char(s, ',');
|
||||
}
|
||||
|
||||
ofputil_format_port(bundle->slaves[i], port_map, s);
|
||||
ofputil_format_port(bundle->members[i], port_map, s);
|
||||
}
|
||||
|
||||
ds_put_format(s, "%s)%s", colors.paren, colors.end);
|
||||
|
@ -40,11 +40,11 @@ struct ofputil_port_map;
|
||||
*
|
||||
* See lib/ofp-actions.c for NXAST_BUNDLE specification. */
|
||||
|
||||
#define BUNDLE_MAX_SLAVES 2048
|
||||
#define BUNDLE_MAX_MEMBERS 2048
|
||||
|
||||
ofp_port_t bundle_execute(const struct ofpact_bundle *, const struct flow *,
|
||||
struct flow_wildcards *wc,
|
||||
bool (*slave_enabled)(ofp_port_t ofp_port, void *aux),
|
||||
bool (*member_enabled)(ofp_port_t ofp_port, void *aux),
|
||||
void *aux);
|
||||
enum ofperr bundle_check(const struct ofpact_bundle *, ofp_port_t max_ports,
|
||||
const struct match *);
|
||||
|
@ -780,8 +780,8 @@ cfm_process_heartbeat(struct cfm *cfm, const struct dp_packet *p)
|
||||
*
|
||||
* Faults can cause a controller or Open vSwitch to make potentially
|
||||
* expensive changes to the network topology. It seems prudent to trigger
|
||||
* them judiciously, especially when CFM is used to check slave status of
|
||||
* bonds. Furthermore, faults can be maliciously triggered by crafting
|
||||
* them judiciously, especially when CFM is used to check status of bond
|
||||
* members. Furthermore, faults can be maliciously triggered by crafting
|
||||
* unexpected CCMs. */
|
||||
if (memcmp(ccm->maid, cfm->maid, sizeof ccm->maid)) {
|
||||
cfm->recv_fault |= CFM_FAULT_MAID;
|
||||
|
@ -629,9 +629,9 @@ struct tx_port {
|
||||
struct dp_netdev_rxq *output_pkts_rxqs[NETDEV_MAX_BURST];
|
||||
};
|
||||
|
||||
/* Contained by struct tx_bond 'slave_buckets'. */
|
||||
struct slave_entry {
|
||||
odp_port_t slave_id;
|
||||
/* Contained by struct tx_bond 'member_buckets'. */
|
||||
struct member_entry {
|
||||
odp_port_t member_id;
|
||||
atomic_ullong n_packets;
|
||||
atomic_ullong n_bytes;
|
||||
};
|
||||
@ -640,7 +640,7 @@ struct slave_entry {
|
||||
struct tx_bond {
|
||||
struct cmap_node node;
|
||||
uint32_t bond_id;
|
||||
struct slave_entry slave_buckets[BOND_BUCKETS];
|
||||
struct member_entry member_buckets[BOND_BUCKETS];
|
||||
};
|
||||
|
||||
/* A set of properties for the current processing loop that is not directly
|
||||
@ -1588,17 +1588,17 @@ dpif_netdev_bond_show(struct unixctl_conn *conn, int argc,
|
||||
|
||||
if (cmap_count(&dp->tx_bonds) > 0) {
|
||||
struct tx_bond *dp_bond_entry;
|
||||
uint32_t slave_id;
|
||||
|
||||
ds_put_cstr(&reply, "Bonds:\n");
|
||||
CMAP_FOR_EACH (dp_bond_entry, node, &dp->tx_bonds) {
|
||||
ds_put_format(&reply, " bond-id %"PRIu32":\n",
|
||||
dp_bond_entry->bond_id);
|
||||
for (int bucket = 0; bucket < BOND_BUCKETS; bucket++) {
|
||||
slave_id =
|
||||
odp_to_u32(dp_bond_entry->slave_buckets[bucket].slave_id);
|
||||
ds_put_format(&reply, " bucket %d - slave %"PRIu32"\n",
|
||||
bucket, slave_id);
|
||||
uint32_t member_id = odp_to_u32(
|
||||
dp_bond_entry->member_buckets[bucket].member_id);
|
||||
ds_put_format(&reply,
|
||||
" bucket %d - member %"PRIu32"\n",
|
||||
bucket, member_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6710,10 +6710,10 @@ dp_netdev_add_bond_tx_to_pmd(struct dp_netdev_pmd_thread *pmd,
|
||||
for (int i = 0; i < BOND_BUCKETS; i++) {
|
||||
uint64_t n_packets, n_bytes;
|
||||
|
||||
atomic_read_relaxed(&tx->slave_buckets[i].n_packets, &n_packets);
|
||||
atomic_read_relaxed(&tx->slave_buckets[i].n_bytes, &n_bytes);
|
||||
atomic_init(&new_tx->slave_buckets[i].n_packets, n_packets);
|
||||
atomic_init(&new_tx->slave_buckets[i].n_bytes, n_bytes);
|
||||
atomic_read_relaxed(&tx->member_buckets[i].n_packets, &n_packets);
|
||||
atomic_read_relaxed(&tx->member_buckets[i].n_bytes, &n_bytes);
|
||||
atomic_init(&new_tx->member_buckets[i].n_packets, n_packets);
|
||||
atomic_init(&new_tx->member_buckets[i].n_bytes, n_bytes);
|
||||
}
|
||||
cmap_replace(&pmd->tx_bonds, &tx->node, &new_tx->node,
|
||||
hash_bond_id(bond->bond_id));
|
||||
@ -7639,18 +7639,19 @@ dp_execute_lb_output_action(struct dp_netdev_pmd_thread *pmd,
|
||||
|
||||
DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) {
|
||||
/*
|
||||
* Lookup the bond-hash table using hash to get the slave.
|
||||
* Lookup the bond-hash table using hash to get the member.
|
||||
*/
|
||||
uint32_t hash = dp_packet_get_rss_hash(packet);
|
||||
struct slave_entry *s_entry = &p_bond->slave_buckets[hash & BOND_MASK];
|
||||
odp_port_t bond_member = s_entry->slave_id;
|
||||
struct member_entry *s_entry
|
||||
= &p_bond->member_buckets[hash & BOND_MASK];
|
||||
odp_port_t bond_member = s_entry->member_id;
|
||||
uint32_t size = dp_packet_size(packet);
|
||||
struct dp_packet_batch output_pkt;
|
||||
|
||||
dp_packet_batch_init_packet(&output_pkt, packet);
|
||||
if (OVS_LIKELY(dp_execute_output_action(pmd, &output_pkt, true,
|
||||
bond_member))) {
|
||||
/* Update slave stats. */
|
||||
/* Update member stats. */
|
||||
non_atomic_ullong_add(&s_entry->n_packets, 1);
|
||||
non_atomic_ullong_add(&s_entry->n_bytes, size);
|
||||
}
|
||||
@ -8293,7 +8294,7 @@ dpif_netdev_ipf_dump_done(struct dpif *dpif OVS_UNUSED, void *ipf_dump_ctx)
|
||||
|
||||
static int
|
||||
dpif_netdev_bond_add(struct dpif *dpif, uint32_t bond_id,
|
||||
odp_port_t *slave_map)
|
||||
odp_port_t *member_map)
|
||||
{
|
||||
struct tx_bond *new_tx = xzalloc(sizeof *new_tx);
|
||||
struct dp_netdev *dp = get_dp_netdev(dpif);
|
||||
@ -8302,7 +8303,7 @@ dpif_netdev_bond_add(struct dpif *dpif, uint32_t bond_id,
|
||||
/* Prepare new bond mapping. */
|
||||
new_tx->bond_id = bond_id;
|
||||
for (int bucket = 0; bucket < BOND_BUCKETS; bucket++) {
|
||||
new_tx->slave_buckets[bucket].slave_id = slave_map[bucket];
|
||||
new_tx->member_buckets[bucket].member_id = member_map[bucket];
|
||||
}
|
||||
|
||||
ovs_mutex_lock(&dp->bond_mutex);
|
||||
@ -8375,7 +8376,7 @@ dpif_netdev_bond_stats_get(struct dpif *dpif, uint32_t bond_id,
|
||||
for (int i = 0; i < BOND_BUCKETS; i++) {
|
||||
uint64_t pmd_n_bytes;
|
||||
|
||||
atomic_read_relaxed(&pmd_bond_entry->slave_buckets[i].n_bytes,
|
||||
atomic_read_relaxed(&pmd_bond_entry->member_buckets[i].n_bytes,
|
||||
&pmd_n_bytes);
|
||||
n_bytes[i] += pmd_n_bytes;
|
||||
}
|
||||
|
@ -617,9 +617,9 @@ struct dpif_class {
|
||||
int (*meter_del)(struct dpif *, ofproto_meter_id meter_id,
|
||||
struct ofputil_meter_stats *, uint16_t n_bands);
|
||||
|
||||
/* Adds a bond with 'bond_id' and the slave-map to 'dpif'. */
|
||||
/* Adds a bond with 'bond_id' and the member-map to 'dpif'. */
|
||||
int (*bond_add)(struct dpif *dpif, uint32_t bond_id,
|
||||
odp_port_t *slave_map);
|
||||
odp_port_t *member_map);
|
||||
|
||||
/* Removes bond identified by 'bond_id' from 'dpif'. */
|
||||
int (*bond_del)(struct dpif *dpif, uint32_t bond_id);
|
||||
|
@ -1993,10 +1993,10 @@ dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
|
||||
}
|
||||
|
||||
int
|
||||
dpif_bond_add(struct dpif *dpif, uint32_t bond_id, odp_port_t *slave_map)
|
||||
dpif_bond_add(struct dpif *dpif, uint32_t bond_id, odp_port_t *member_map)
|
||||
{
|
||||
return dpif->dpif_class->bond_del
|
||||
? dpif->dpif_class->bond_add(dpif, bond_id, slave_map)
|
||||
? dpif->dpif_class->bond_add(dpif, bond_id, member_map)
|
||||
: EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
@ -898,7 +898,7 @@ int dpif_meter_del(struct dpif *, ofproto_meter_id meter_id,
|
||||
#define BOND_MASK 0xff
|
||||
#define BOND_BUCKETS (BOND_MASK + 1)
|
||||
|
||||
int dpif_bond_add(struct dpif *, uint32_t bond_id, odp_port_t *slave_map);
|
||||
int dpif_bond_add(struct dpif *, uint32_t bond_id, odp_port_t *member_map);
|
||||
int dpif_bond_del(struct dpif *, uint32_t bond_id);
|
||||
int dpif_bond_stats_get(struct dpif *, uint32_t bond_id, uint64_t *n_bytes);
|
||||
bool dpif_supports_lb_output_action(const struct dpif *);
|
||||
|
539
lib/lacp.c
539
lib/lacp.c
@ -92,12 +92,13 @@ enum pdu_subtype {
|
||||
SUBTYPE_MARKER, /* Link Aggregation Marker Protocol. */
|
||||
};
|
||||
|
||||
enum slave_status {
|
||||
enum member_status {
|
||||
LACP_CURRENT, /* Current State. Partner up to date. */
|
||||
LACP_EXPIRED, /* Expired State. Partner out of date. */
|
||||
LACP_DEFAULTED, /* Defaulted State. No partner. */
|
||||
};
|
||||
|
||||
/* A LACP primary interface. */
|
||||
struct lacp {
|
||||
struct ovs_list node; /* Node in all_lacps list. */
|
||||
char *name; /* Name of this lacp object. */
|
||||
@ -105,8 +106,8 @@ struct lacp {
|
||||
uint16_t sys_priority; /* System Priority. */
|
||||
bool active; /* Active or Passive. */
|
||||
|
||||
struct hmap slaves; /* Slaves this LACP object controls. */
|
||||
struct slave *key_slave; /* Slave whose ID will be the aggregation key. */
|
||||
struct hmap members; /* Members this LACP object controls. */
|
||||
struct member *key_member; /* Member whose ID will be aggregation key. */
|
||||
|
||||
bool fast; /* True if using fast probe interval. */
|
||||
bool negotiated; /* True if LACP negotiations were successful. */
|
||||
@ -116,17 +117,18 @@ struct lacp {
|
||||
struct ovs_refcount ref_cnt;
|
||||
};
|
||||
|
||||
struct slave {
|
||||
void *aux; /* Handle used to identify this slave. */
|
||||
struct hmap_node node; /* Node in master's slaves map. */
|
||||
/* A LACP member interface. */
|
||||
struct member {
|
||||
void *aux; /* Handle used to identify this member. */
|
||||
struct hmap_node node; /* Node in primary's members map. */
|
||||
|
||||
struct lacp *lacp; /* LACP object containing this slave. */
|
||||
struct lacp *lacp; /* LACP object containing this member. */
|
||||
uint16_t port_id; /* Port ID. */
|
||||
uint16_t port_priority; /* Port Priority. */
|
||||
uint16_t key; /* Aggregation Key. 0 if default. */
|
||||
char *name; /* Name of this slave. */
|
||||
char *name; /* Name of this member. */
|
||||
|
||||
enum slave_status status; /* Slave status. */
|
||||
enum member_status status; /* Member status. */
|
||||
bool attached; /* Attached. Traffic may flow. */
|
||||
bool carrier_up; /* Carrier state of link. */
|
||||
struct lacp_info partner; /* Partner information. */
|
||||
@ -149,20 +151,20 @@ static struct ovs_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)
|
||||
static void member_destroy(struct member *) OVS_REQUIRES(mutex);
|
||||
static void member_set_defaulted(struct member *) OVS_REQUIRES(mutex);
|
||||
static void member_set_expired(struct member *) OVS_REQUIRES(mutex);
|
||||
static void member_get_actor(struct member *, struct lacp_info *actor)
|
||||
OVS_REQUIRES(mutex);
|
||||
static void slave_get_priority(struct slave *, struct lacp_info *priority)
|
||||
static void member_get_priority(struct member *, struct lacp_info *priority)
|
||||
OVS_REQUIRES(mutex);
|
||||
static bool slave_may_tx(const struct slave *)
|
||||
static bool member_may_tx(const struct member *)
|
||||
OVS_REQUIRES(mutex);
|
||||
static struct slave *slave_lookup(const struct lacp *, const void *slave)
|
||||
static struct member *member_lookup(const struct lacp *, const void *member)
|
||||
OVS_REQUIRES(mutex);
|
||||
static bool info_tx_equal(struct lacp_info *, struct lacp_info *)
|
||||
OVS_REQUIRES(mutex);
|
||||
static bool slave_may_enable__(struct slave *slave) OVS_REQUIRES(mutex);
|
||||
static bool member_may_enable__(struct member *) OVS_REQUIRES(mutex);
|
||||
|
||||
static unixctl_cb_func lacp_unixctl_show;
|
||||
static unixctl_cb_func lacp_unixctl_show_stats;
|
||||
@ -254,7 +256,7 @@ lacp_create(void) OVS_EXCLUDED(mutex)
|
||||
struct lacp *lacp;
|
||||
|
||||
lacp = xzalloc(sizeof *lacp);
|
||||
hmap_init(&lacp->slaves);
|
||||
hmap_init(&lacp->members);
|
||||
ovs_refcount_init(&lacp->ref_cnt);
|
||||
|
||||
lacp_lock();
|
||||
@ -273,19 +275,19 @@ lacp_ref(const struct lacp *lacp_)
|
||||
return lacp;
|
||||
}
|
||||
|
||||
/* Destroys 'lacp' and its slaves. Does nothing if 'lacp' is NULL. */
|
||||
/* Destroys 'lacp' and its members. Does nothing if 'lacp' is NULL. */
|
||||
void
|
||||
lacp_unref(struct lacp *lacp) OVS_EXCLUDED(mutex)
|
||||
{
|
||||
if (lacp && ovs_refcount_unref_relaxed(&lacp->ref_cnt) == 1) {
|
||||
struct slave *slave, *next;
|
||||
struct member *member, *next;
|
||||
|
||||
lacp_lock();
|
||||
HMAP_FOR_EACH_SAFE (slave, next, node, &lacp->slaves) {
|
||||
slave_destroy(slave);
|
||||
HMAP_FOR_EACH_SAFE (member, next, node, &lacp->members) {
|
||||
member_destroy(member);
|
||||
}
|
||||
|
||||
hmap_destroy(&lacp->slaves);
|
||||
hmap_destroy(&lacp->members);
|
||||
ovs_list_remove(&lacp->node);
|
||||
free(lacp->name);
|
||||
free(lacp);
|
||||
@ -336,39 +338,40 @@ lacp_is_active(const struct lacp *lacp) OVS_EXCLUDED(mutex)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Processes 'packet' which was received on 'slave_'. This function should be
|
||||
* called on all packets received on 'slave_' with Ethernet Type ETH_TYPE_LACP.
|
||||
/* Processes 'packet' which was received on 'member_'. This function should be
|
||||
* called on all packets received on 'member_' with Ethernet Type
|
||||
* ETH_TYPE_LACP.
|
||||
*/
|
||||
bool
|
||||
lacp_process_packet(struct lacp *lacp, const void *slave_,
|
||||
lacp_process_packet(struct lacp *lacp, const void *member_,
|
||||
const struct dp_packet *packet)
|
||||
OVS_EXCLUDED(mutex)
|
||||
{
|
||||
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
|
||||
const struct lacp_pdu *pdu;
|
||||
long long int tx_rate;
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
bool lacp_may_enable = false;
|
||||
enum pdu_subtype subtype;
|
||||
|
||||
lacp_lock();
|
||||
slave = slave_lookup(lacp, slave_);
|
||||
if (!slave) {
|
||||
member = member_lookup(lacp, member_);
|
||||
if (!member) {
|
||||
goto out;
|
||||
}
|
||||
slave->count_rx_pdus++;
|
||||
member->count_rx_pdus++;
|
||||
|
||||
pdu = parse_lacp_packet(packet, &subtype);
|
||||
switch (subtype) {
|
||||
case SUBTYPE_LACP:
|
||||
break;
|
||||
case SUBTYPE_MARKER:
|
||||
slave->count_rx_pdus_marker++;
|
||||
member->count_rx_pdus_marker++;
|
||||
VLOG_DBG("%s: received a LACP marker PDU.", lacp->name);
|
||||
goto out;
|
||||
case SUBTYPE_UNUSED:
|
||||
default:
|
||||
slave->count_rx_pdus_bad++;
|
||||
member->count_rx_pdus_bad++;
|
||||
VLOG_WARN_RL(&rl, "%s: received an unparsable LACP PDU.",
|
||||
lacp->name);
|
||||
goto out;
|
||||
@ -377,30 +380,30 @@ lacp_process_packet(struct lacp *lacp, const void *slave_,
|
||||
/* On some NICs L1 state reporting is slow. In case LACP packets are
|
||||
* received while carrier (L1) state is still down, drop the LACP PDU and
|
||||
* trigger re-checking of L1 state. */
|
||||
if (!slave->carrier_up) {
|
||||
if (!member->carrier_up) {
|
||||
VLOG_INFO_RL(&rl, "%s: carrier state is DOWN,"
|
||||
" dropping received LACP PDU.", slave->name);
|
||||
" dropping received LACP PDU.", member->name);
|
||||
seq_change(connectivity_seq_get());
|
||||
goto out;
|
||||
}
|
||||
|
||||
slave->status = LACP_CURRENT;
|
||||
member->status = LACP_CURRENT;
|
||||
tx_rate = lacp->fast ? LACP_FAST_TIME_TX : LACP_SLOW_TIME_TX;
|
||||
timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * tx_rate);
|
||||
timer_set_duration(&member->rx, LACP_RX_MULTIPLIER * tx_rate);
|
||||
|
||||
slave->ntt_actor = pdu->partner;
|
||||
member->ntt_actor = pdu->partner;
|
||||
|
||||
/* Update our information about our partner if it's out of date. This may
|
||||
* cause priorities to change so re-calculate attached status of all
|
||||
* slaves. */
|
||||
if (memcmp(&slave->partner, &pdu->actor, sizeof pdu->actor)) {
|
||||
* members. */
|
||||
if (memcmp(&member->partner, &pdu->actor, sizeof pdu->actor)) {
|
||||
lacp->update = true;
|
||||
slave->partner = pdu->actor;
|
||||
member->partner = pdu->actor;
|
||||
}
|
||||
|
||||
/* Evaluate may_enable here to avoid dropping of packets till main thread
|
||||
* sets may_enable to true. */
|
||||
lacp_may_enable = slave_may_enable__(slave);
|
||||
lacp_may_enable = member_may_enable__(member);
|
||||
|
||||
out:
|
||||
lacp_unlock();
|
||||
@ -426,92 +429,92 @@ lacp_status(const struct lacp *lacp) OVS_EXCLUDED(mutex)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 settings change. */
|
||||
/* Registers 'member_' as subordinate to 'lacp'. This should be called at
|
||||
* least once per member in a LACP managed bond. Should also be called
|
||||
* whenever a member's settings change. */
|
||||
void
|
||||
lacp_slave_register(struct lacp *lacp, void *slave_,
|
||||
const struct lacp_slave_settings *s)
|
||||
lacp_member_register(struct lacp *lacp, void *member_,
|
||||
const struct lacp_member_settings *s)
|
||||
OVS_EXCLUDED(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
|
||||
lacp_lock();
|
||||
slave = slave_lookup(lacp, slave_);
|
||||
if (!slave) {
|
||||
slave = xzalloc(sizeof *slave);
|
||||
slave->lacp = lacp;
|
||||
slave->aux = slave_;
|
||||
hmap_insert(&lacp->slaves, &slave->node, hash_pointer(slave_, 0));
|
||||
slave_set_defaulted(slave);
|
||||
member = member_lookup(lacp, member_);
|
||||
if (!member) {
|
||||
member = xzalloc(sizeof *member);
|
||||
member->lacp = lacp;
|
||||
member->aux = member_;
|
||||
hmap_insert(&lacp->members, &member->node, hash_pointer(member_, 0));
|
||||
member_set_defaulted(member);
|
||||
|
||||
if (!lacp->key_slave) {
|
||||
lacp->key_slave = slave;
|
||||
if (!lacp->key_member) {
|
||||
lacp->key_member = member;
|
||||
}
|
||||
}
|
||||
|
||||
if (!slave->name || strcmp(s->name, slave->name)) {
|
||||
free(slave->name);
|
||||
slave->name = xstrdup(s->name);
|
||||
if (!member->name || strcmp(s->name, member->name)) {
|
||||
free(member->name);
|
||||
member->name = xstrdup(s->name);
|
||||
}
|
||||
|
||||
if (slave->port_id != s->id
|
||||
|| slave->port_priority != s->priority
|
||||
|| slave->key != s->key) {
|
||||
slave->port_id = s->id;
|
||||
slave->port_priority = s->priority;
|
||||
slave->key = s->key;
|
||||
if (member->port_id != s->id
|
||||
|| member->port_priority != s->priority
|
||||
|| member->key != s->key) {
|
||||
member->port_id = s->id;
|
||||
member->port_priority = s->priority;
|
||||
member->key = s->key;
|
||||
|
||||
lacp->update = true;
|
||||
|
||||
if (lacp->active || lacp->negotiated) {
|
||||
slave_set_expired(slave);
|
||||
member_set_expired(member);
|
||||
}
|
||||
}
|
||||
lacp_unlock();
|
||||
}
|
||||
|
||||
/* Unregisters 'slave_' with 'lacp'. */
|
||||
/* Unregisters 'member_' with 'lacp'. */
|
||||
void
|
||||
lacp_slave_unregister(struct lacp *lacp, const void *slave_)
|
||||
lacp_member_unregister(struct lacp *lacp, const void *member_)
|
||||
OVS_EXCLUDED(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
|
||||
lacp_lock();
|
||||
slave = slave_lookup(lacp, slave_);
|
||||
if (slave) {
|
||||
slave_destroy(slave);
|
||||
member = member_lookup(lacp, member_);
|
||||
if (member) {
|
||||
member_destroy(member);
|
||||
lacp->update = true;
|
||||
}
|
||||
lacp_unlock();
|
||||
}
|
||||
|
||||
/* This function should be called whenever the carrier status of 'slave_' has
|
||||
/* This function should be called whenever the carrier status of 'member_' has
|
||||
* changed. If 'lacp' is null, this function has no effect.*/
|
||||
void
|
||||
lacp_slave_carrier_changed(const struct lacp *lacp, const void *slave_,
|
||||
lacp_member_carrier_changed(const struct lacp *lacp, const void *member_,
|
||||
bool carrier_up)
|
||||
OVS_EXCLUDED(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
if (!lacp) {
|
||||
return;
|
||||
}
|
||||
|
||||
lacp_lock();
|
||||
slave = slave_lookup(lacp, slave_);
|
||||
if (!slave) {
|
||||
member = member_lookup(lacp, member_);
|
||||
if (!member) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (slave->status == LACP_CURRENT || slave->lacp->active) {
|
||||
slave_set_expired(slave);
|
||||
if (member->status == LACP_CURRENT || member->lacp->active) {
|
||||
member_set_expired(member);
|
||||
}
|
||||
|
||||
if (slave->carrier_up != carrier_up) {
|
||||
slave->carrier_up = carrier_up;
|
||||
slave->count_carrier_changed++;
|
||||
if (member->carrier_up != carrier_up) {
|
||||
member->carrier_up = carrier_up;
|
||||
member->count_carrier_changed++;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -519,35 +522,35 @@ out:
|
||||
}
|
||||
|
||||
static bool
|
||||
slave_may_enable__(struct slave *slave) OVS_REQUIRES(mutex)
|
||||
member_may_enable__(struct member *member) OVS_REQUIRES(mutex)
|
||||
{
|
||||
/* The slave may be enabled if it's attached to an aggregator and its
|
||||
/* The member may be enabled if it's attached to an aggregator and its
|
||||
* partner is synchronized.*/
|
||||
return slave->attached && (slave->partner.state & LACP_STATE_SYNC
|
||||
|| (slave->lacp && slave->lacp->fallback_ab
|
||||
&& slave->status == LACP_DEFAULTED));
|
||||
return member->attached && (member->partner.state & LACP_STATE_SYNC
|
||||
|| (member->lacp && member->lacp->fallback_ab
|
||||
&& member->status == LACP_DEFAULTED));
|
||||
}
|
||||
|
||||
/* This function should be called before enabling 'slave_' to send or receive
|
||||
* traffic. If it returns false, 'slave_' should not enabled. As a
|
||||
/* This function should be called before enabling 'member_' to send or receive
|
||||
* traffic. If it returns false, 'member_' should not enabled. As a
|
||||
* convenience, returns true if 'lacp' is NULL. */
|
||||
bool
|
||||
lacp_slave_may_enable(const struct lacp *lacp, const void *slave_)
|
||||
lacp_member_may_enable(const struct lacp *lacp, const void *member_)
|
||||
OVS_EXCLUDED(mutex)
|
||||
{
|
||||
if (lacp) {
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
bool ret = false;
|
||||
|
||||
lacp_lock();
|
||||
slave = slave_lookup(lacp, slave_);
|
||||
if (slave) {
|
||||
/* It is only called when carrier is up. So, enable slave's
|
||||
member = member_lookup(lacp, member_);
|
||||
if (member) {
|
||||
/* It is only called when carrier is up. So, enable member's
|
||||
* carrier state if it is currently down. */
|
||||
if (!slave->carrier_up) {
|
||||
slave->carrier_up = true;
|
||||
if (!member->carrier_up) {
|
||||
member->carrier_up = true;
|
||||
}
|
||||
ret = slave_may_enable__(slave);
|
||||
ret = member_may_enable__(member);
|
||||
}
|
||||
lacp_unlock();
|
||||
return ret;
|
||||
@ -556,19 +559,19 @@ lacp_slave_may_enable(const struct lacp *lacp, const void *slave_)
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if partner information on 'slave_' is up to date. 'slave_'
|
||||
/* Returns true if partner information on 'member_' is up to date. 'member_'
|
||||
* 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_)
|
||||
lacp_member_is_current(const struct lacp *lacp, const void *member_)
|
||||
OVS_EXCLUDED(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
bool ret;
|
||||
|
||||
lacp_lock();
|
||||
slave = slave_lookup(lacp, slave_);
|
||||
ret = slave ? slave->status != LACP_DEFAULTED : false;
|
||||
member = member_lookup(lacp, member_);
|
||||
ret = member ? member->status != LACP_DEFAULTED : false;
|
||||
lacp_unlock();
|
||||
return ret;
|
||||
}
|
||||
@ -577,21 +580,21 @@ lacp_slave_is_current(const struct lacp *lacp, const void *slave_)
|
||||
void
|
||||
lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
|
||||
lacp_lock();
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
if (timer_expired(&slave->rx)) {
|
||||
enum slave_status old_status = slave->status;
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
if (timer_expired(&member->rx)) {
|
||||
enum member_status old_status = member->status;
|
||||
|
||||
if (slave->status == LACP_CURRENT) {
|
||||
slave_set_expired(slave);
|
||||
slave->count_link_expired++;
|
||||
} else if (slave->status == LACP_EXPIRED) {
|
||||
slave_set_defaulted(slave);
|
||||
slave->count_link_defaulted++;
|
||||
if (member->status == LACP_CURRENT) {
|
||||
member_set_expired(member);
|
||||
member->count_link_expired++;
|
||||
} else if (member->status == LACP_EXPIRED) {
|
||||
member_set_defaulted(member);
|
||||
member->count_link_defaulted++;
|
||||
}
|
||||
if (slave->status != old_status) {
|
||||
if (member->status != old_status) {
|
||||
seq_change(connectivity_seq_get());
|
||||
}
|
||||
}
|
||||
@ -602,30 +605,30 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
|
||||
seq_change(connectivity_seq_get());
|
||||
}
|
||||
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
struct lacp_info actor;
|
||||
|
||||
if (!slave_may_tx(slave)) {
|
||||
if (!member_may_tx(member)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
slave_get_actor(slave, &actor);
|
||||
member_get_actor(member, &actor);
|
||||
|
||||
if (timer_expired(&slave->tx)
|
||||
|| !info_tx_equal(&actor, &slave->ntt_actor)) {
|
||||
if (timer_expired(&member->tx)
|
||||
|| !info_tx_equal(&actor, &member->ntt_actor)) {
|
||||
long long int duration;
|
||||
struct lacp_pdu pdu;
|
||||
|
||||
slave->ntt_actor = actor;
|
||||
compose_lacp_pdu(&actor, &slave->partner, &pdu);
|
||||
send_pdu(slave->aux, &pdu, sizeof pdu);
|
||||
slave->count_tx_pdus++;
|
||||
member->ntt_actor = actor;
|
||||
compose_lacp_pdu(&actor, &member->partner, &pdu);
|
||||
send_pdu(member->aux, &pdu, sizeof pdu);
|
||||
member->count_tx_pdus++;
|
||||
|
||||
duration = (slave->partner.state & LACP_STATE_TIME
|
||||
duration = (member->partner.state & LACP_STATE_TIME
|
||||
? LACP_FAST_TIME_TX
|
||||
: LACP_SLOW_TIME_TX);
|
||||
|
||||
timer_set_duration(&slave->tx, duration);
|
||||
timer_set_duration(&member->tx, duration);
|
||||
seq_change(connectivity_seq_get());
|
||||
}
|
||||
}
|
||||
@ -636,16 +639,16 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
|
||||
void
|
||||
lacp_wait(struct lacp *lacp) OVS_EXCLUDED(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
|
||||
lacp_lock();
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
if (slave_may_tx(slave)) {
|
||||
timer_wait(&slave->tx);
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
if (member_may_tx(member)) {
|
||||
timer_wait(&member->tx);
|
||||
}
|
||||
|
||||
if (slave->status != LACP_DEFAULTED) {
|
||||
timer_wait(&slave->rx);
|
||||
if (member->status != LACP_DEFAULTED) {
|
||||
timer_wait(&member->rx);
|
||||
}
|
||||
}
|
||||
lacp_unlock();
|
||||
@ -653,12 +656,12 @@ lacp_wait(struct lacp *lacp) OVS_EXCLUDED(mutex)
|
||||
|
||||
/* Static Helpers. */
|
||||
|
||||
/* Updates the attached status of all slaves controlled by 'lacp' and sets its
|
||||
* negotiated parameter to true if any slaves are attachable. */
|
||||
/* Updates the attached status of all members controlled by 'lacp' and sets its
|
||||
* negotiated parameter to true if any members are attachable. */
|
||||
static void
|
||||
lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
{
|
||||
struct slave *lead, *lead_current, *slave;
|
||||
struct member *lead, *lead_current, *member;
|
||||
struct lacp_info lead_pri;
|
||||
bool lead_enable;
|
||||
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
|
||||
@ -671,12 +674,12 @@ lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
|
||||
/* Check if there is a working interface.
|
||||
* Store as lead_current, if there is one. */
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
if (slave->status == LACP_CURRENT && slave->attached) {
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
if (member->status == LACP_CURRENT && member->attached) {
|
||||
struct lacp_info pri;
|
||||
slave_get_priority(slave, &pri);
|
||||
member_get_priority(member, &pri);
|
||||
if (!lead_current || memcmp(&pri, &lead_pri, sizeof pri) < 0) {
|
||||
lead_current = slave;
|
||||
lead_current = member;
|
||||
lead = lead_current;
|
||||
lead_pri = pri;
|
||||
lead_enable = true;
|
||||
@ -685,43 +688,43 @@ lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
}
|
||||
|
||||
/* Find interface with highest priority. */
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
struct lacp_info pri;
|
||||
|
||||
slave->attached = false;
|
||||
member->attached = false;
|
||||
|
||||
/* XXX: In the future allow users to configure the expected system ID.
|
||||
* For now just special case loopback. */
|
||||
if (eth_addr_equals(slave->partner.sys_id, slave->lacp->sys_id)) {
|
||||
VLOG_WARN_RL(&rl, "slave %s: Loopback detected. Slave is "
|
||||
"connected to its own bond", slave->name);
|
||||
if (eth_addr_equals(member->partner.sys_id, member->lacp->sys_id)) {
|
||||
VLOG_WARN_RL(&rl, "member %s: Loopback detected. Interface is "
|
||||
"connected to its own bond", member->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slave->status == LACP_DEFAULTED) {
|
||||
if (member->status == LACP_DEFAULTED) {
|
||||
if (lacp->fallback_ab) {
|
||||
slave->attached = true;
|
||||
member->attached = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
slave_get_priority(slave, &pri);
|
||||
bool enable = slave_may_enable__(slave);
|
||||
member_get_priority(member, &pri);
|
||||
bool enable = member_may_enable__(member);
|
||||
|
||||
/* Check if partner MAC address is the same as on the working
|
||||
* interface. Activate slave only if the MAC is the same, or
|
||||
* interface. Activate member only if the MAC is the same, or
|
||||
* there is no working interface. */
|
||||
if (!lead_current || (lead_current
|
||||
&& eth_addr_equals(slave->partner.sys_id,
|
||||
&& eth_addr_equals(member->partner.sys_id,
|
||||
lead_current->partner.sys_id))) {
|
||||
slave->attached = true;
|
||||
member->attached = true;
|
||||
}
|
||||
if (slave->attached &&
|
||||
if (member->attached &&
|
||||
(!lead
|
||||
|| enable > lead_enable
|
||||
|| (enable == lead_enable
|
||||
&& memcmp(&pri, &lead_pri, sizeof pri) < 0))) {
|
||||
lead = slave;
|
||||
lead = member;
|
||||
lead_enable = enable;
|
||||
lead_pri = pri;
|
||||
}
|
||||
@ -730,65 +733,66 @@ lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
lacp->negotiated = lead != NULL;
|
||||
|
||||
if (lead) {
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
if ((lacp->fallback_ab && slave->status == LACP_DEFAULTED)
|
||||
|| lead->partner.key != slave->partner.key
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
if ((lacp->fallback_ab && member->status == LACP_DEFAULTED)
|
||||
|| lead->partner.key != member->partner.key
|
||||
|| !eth_addr_equals(lead->partner.sys_id,
|
||||
slave->partner.sys_id)) {
|
||||
slave->attached = false;
|
||||
member->partner.sys_id)) {
|
||||
member->attached = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
slave_destroy(struct slave *slave) OVS_REQUIRES(mutex)
|
||||
member_destroy(struct member *member) OVS_REQUIRES(mutex)
|
||||
{
|
||||
if (slave) {
|
||||
struct lacp *lacp = slave->lacp;
|
||||
if (member) {
|
||||
struct lacp *lacp = member->lacp;
|
||||
|
||||
lacp->update = true;
|
||||
hmap_remove(&lacp->slaves, &slave->node);
|
||||
hmap_remove(&lacp->members, &member->node);
|
||||
|
||||
if (lacp->key_slave == slave) {
|
||||
struct hmap_node *slave_node = hmap_first(&lacp->slaves);
|
||||
if (lacp->key_member == member) {
|
||||
struct hmap_node *member_node = hmap_first(&lacp->members);
|
||||
|
||||
if (slave_node) {
|
||||
lacp->key_slave = CONTAINER_OF(slave_node, struct slave, node);
|
||||
if (member_node) {
|
||||
lacp->key_member = CONTAINER_OF(member_node, struct member,
|
||||
node);
|
||||
} else {
|
||||
lacp->key_slave = NULL;
|
||||
lacp->key_member = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(slave->name);
|
||||
free(slave);
|
||||
free(member->name);
|
||||
free(member);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
slave_set_defaulted(struct slave *slave) OVS_REQUIRES(mutex)
|
||||
member_set_defaulted(struct member *member) OVS_REQUIRES(mutex)
|
||||
{
|
||||
memset(&slave->partner, 0, sizeof slave->partner);
|
||||
memset(&member->partner, 0, sizeof member->partner);
|
||||
|
||||
slave->lacp->update = true;
|
||||
slave->status = LACP_DEFAULTED;
|
||||
member->lacp->update = true;
|
||||
member->status = LACP_DEFAULTED;
|
||||
}
|
||||
|
||||
static void
|
||||
slave_set_expired(struct slave *slave) OVS_REQUIRES(mutex)
|
||||
member_set_expired(struct member *member) OVS_REQUIRES(mutex)
|
||||
{
|
||||
slave->status = LACP_EXPIRED;
|
||||
slave->partner.state |= LACP_STATE_TIME;
|
||||
slave->partner.state &= ~LACP_STATE_SYNC;
|
||||
member->status = LACP_EXPIRED;
|
||||
member->partner.state |= LACP_STATE_TIME;
|
||||
member->partner.state &= ~LACP_STATE_SYNC;
|
||||
|
||||
timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX);
|
||||
timer_set_duration(&member->rx, LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX);
|
||||
}
|
||||
|
||||
static void
|
||||
slave_get_actor(struct slave *slave, struct lacp_info *actor)
|
||||
member_get_actor(struct member *member, struct lacp_info *actor)
|
||||
OVS_REQUIRES(mutex)
|
||||
{
|
||||
struct lacp *lacp = slave->lacp;
|
||||
struct lacp *lacp = member->lacp;
|
||||
uint16_t key;
|
||||
uint8_t state = 0;
|
||||
|
||||
@ -800,62 +804,62 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor)
|
||||
state |= LACP_STATE_TIME;
|
||||
}
|
||||
|
||||
if (slave->attached) {
|
||||
if (member->attached) {
|
||||
state |= LACP_STATE_SYNC;
|
||||
}
|
||||
|
||||
if (slave->status == LACP_DEFAULTED) {
|
||||
if (member->status == LACP_DEFAULTED) {
|
||||
state |= LACP_STATE_DEF;
|
||||
}
|
||||
|
||||
if (slave->status == LACP_EXPIRED) {
|
||||
if (member->status == LACP_EXPIRED) {
|
||||
state |= LACP_STATE_EXP;
|
||||
}
|
||||
|
||||
if (hmap_count(&lacp->slaves) > 1) {
|
||||
if (hmap_count(&lacp->members) > 1) {
|
||||
state |= LACP_STATE_AGG;
|
||||
}
|
||||
|
||||
if (slave->attached || !lacp->negotiated) {
|
||||
if (member->attached || !lacp->negotiated) {
|
||||
state |= LACP_STATE_COL | LACP_STATE_DIST;
|
||||
}
|
||||
|
||||
key = lacp->key_slave->key;
|
||||
key = lacp->key_member->key;
|
||||
if (!key) {
|
||||
key = lacp->key_slave->port_id;
|
||||
key = lacp->key_member->port_id;
|
||||
}
|
||||
|
||||
actor->state = state;
|
||||
actor->key = htons(key);
|
||||
actor->port_priority = htons(slave->port_priority);
|
||||
actor->port_id = htons(slave->port_id);
|
||||
actor->port_priority = htons(member->port_priority);
|
||||
actor->port_id = htons(member->port_id);
|
||||
actor->sys_priority = htons(lacp->sys_priority);
|
||||
actor->sys_id = lacp->sys_id;
|
||||
}
|
||||
|
||||
/* Given 'slave', populates 'priority' with data representing its LACP link
|
||||
/* Given 'member', populates 'priority' with data representing its LACP link
|
||||
* priority. If two priority objects populated by this function are compared
|
||||
* using memcmp, the higher priority link will be less than the lower priority
|
||||
* link. */
|
||||
static void
|
||||
slave_get_priority(struct slave *slave, struct lacp_info *priority)
|
||||
member_get_priority(struct member *member, struct lacp_info *priority)
|
||||
OVS_REQUIRES(mutex)
|
||||
{
|
||||
uint16_t partner_priority, actor_priority;
|
||||
|
||||
/* Choose the lacp_info of the higher priority system by comparing their
|
||||
* system priorities and mac addresses. */
|
||||
actor_priority = slave->lacp->sys_priority;
|
||||
partner_priority = ntohs(slave->partner.sys_priority);
|
||||
actor_priority = member->lacp->sys_priority;
|
||||
partner_priority = ntohs(member->partner.sys_priority);
|
||||
if (actor_priority < partner_priority) {
|
||||
slave_get_actor(slave, priority);
|
||||
member_get_actor(member, priority);
|
||||
} else if (partner_priority < actor_priority) {
|
||||
*priority = slave->partner;
|
||||
} else if (eth_addr_compare_3way(slave->lacp->sys_id,
|
||||
slave->partner.sys_id) < 0) {
|
||||
slave_get_actor(slave, priority);
|
||||
*priority = member->partner;
|
||||
} else if (eth_addr_compare_3way(member->lacp->sys_id,
|
||||
member->partner.sys_id) < 0) {
|
||||
member_get_actor(member, priority);
|
||||
} else {
|
||||
*priority = slave->partner;
|
||||
*priority = member->partner;
|
||||
}
|
||||
|
||||
/* Key and state are not used in priority comparisons. */
|
||||
@ -864,22 +868,22 @@ slave_get_priority(struct slave *slave, struct lacp_info *priority)
|
||||
}
|
||||
|
||||
static bool
|
||||
slave_may_tx(const struct slave *slave) OVS_REQUIRES(mutex)
|
||||
member_may_tx(const struct member *member) OVS_REQUIRES(mutex)
|
||||
{
|
||||
/* Check for L1 state as well as LACP state. */
|
||||
return (slave->carrier_up) && ((slave->lacp->active) ||
|
||||
(slave->status != LACP_DEFAULTED));
|
||||
return (member->carrier_up) && ((member->lacp->active) ||
|
||||
(member->status != LACP_DEFAULTED));
|
||||
}
|
||||
|
||||
static struct slave *
|
||||
slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQUIRES(mutex)
|
||||
static struct member *
|
||||
member_lookup(const struct lacp *lacp, const void *member_) OVS_REQUIRES(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
|
||||
HMAP_FOR_EACH_IN_BUCKET (slave, node, hash_pointer(slave_, 0),
|
||||
&lacp->slaves) {
|
||||
if (slave->aux == slave_) {
|
||||
return slave;
|
||||
HMAP_FOR_EACH_IN_BUCKET (member, node, hash_pointer(member_, 0),
|
||||
&lacp->members) {
|
||||
if (member->aux == member_) {
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
||||
@ -961,10 +965,10 @@ ds_put_lacp_state(struct ds *ds, uint8_t state)
|
||||
static void
|
||||
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;
|
||||
struct shash member_shash = SHASH_INITIALIZER(&member_shash);
|
||||
const struct shash_node **sorted_members = NULL;
|
||||
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
int i;
|
||||
|
||||
ds_put_format(ds, "---- %s ----\n", lacp->name);
|
||||
@ -977,10 +981,10 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
ds_put_format(ds, " sys_id: " ETH_ADDR_FMT "\n", ETH_ADDR_ARGS(lacp->sys_id));
|
||||
ds_put_format(ds, " sys_priority: %u\n", lacp->sys_priority);
|
||||
ds_put_cstr(ds, " aggregation key: ");
|
||||
if (lacp->key_slave) {
|
||||
ds_put_format(ds, "%u", lacp->key_slave->key
|
||||
? lacp->key_slave->key
|
||||
: lacp->key_slave->port_id);
|
||||
if (lacp->key_member) {
|
||||
ds_put_format(ds, "%u", lacp->key_member->key
|
||||
? lacp->key_member->key
|
||||
: lacp->key_member->port_id);
|
||||
} else {
|
||||
ds_put_cstr(ds, "none");
|
||||
}
|
||||
@ -993,18 +997,18 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
ds_put_cstr(ds, "slow\n");
|
||||
}
|
||||
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
shash_add(&slave_shash, slave->name, slave);
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
shash_add(&member_shash, member->name, member);
|
||||
}
|
||||
sorted_slaves = shash_sort(&slave_shash);
|
||||
sorted_members = shash_sort(&member_shash);
|
||||
|
||||
for (i = 0; i < shash_count(&slave_shash); i++) {
|
||||
for (i = 0; i < shash_count(&member_shash); i++) {
|
||||
char *status;
|
||||
struct lacp_info actor;
|
||||
|
||||
slave = sorted_slaves[i]->data;
|
||||
slave_get_actor(slave, &actor);
|
||||
switch (slave->status) {
|
||||
member = sorted_members[i]->data;
|
||||
member_get_actor(member, &actor);
|
||||
switch (member->status) {
|
||||
case LACP_CURRENT:
|
||||
status = "current";
|
||||
break;
|
||||
@ -1018,11 +1022,11 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
OVS_NOT_REACHED();
|
||||
}
|
||||
|
||||
ds_put_format(ds, "\nslave: %s: %s %s\n", slave->name, status,
|
||||
slave->attached ? "attached" : "detached");
|
||||
ds_put_format(ds, " port_id: %u\n", slave->port_id);
|
||||
ds_put_format(ds, " port_priority: %u\n", slave->port_priority);
|
||||
ds_put_format(ds, " may_enable: %s\n", (slave_may_enable__(slave)
|
||||
ds_put_format(ds, "\nmember: %s: %s %s\n", member->name, status,
|
||||
member->attached ? "attached" : "detached");
|
||||
ds_put_format(ds, " port_id: %u\n", member->port_id);
|
||||
ds_put_format(ds, " port_priority: %u\n", member->port_priority);
|
||||
ds_put_format(ds, " may_enable: %s\n", (member_may_enable__(member)
|
||||
? "true" : "false"));
|
||||
|
||||
ds_put_format(ds, "\n actor sys_id: " ETH_ADDR_FMT "\n",
|
||||
@ -1040,58 +1044,58 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
ds_put_cstr(ds, "\n\n");
|
||||
|
||||
ds_put_format(ds, " partner sys_id: " ETH_ADDR_FMT "\n",
|
||||
ETH_ADDR_ARGS(slave->partner.sys_id));
|
||||
ETH_ADDR_ARGS(member->partner.sys_id));
|
||||
ds_put_format(ds, " partner sys_priority: %u\n",
|
||||
ntohs(slave->partner.sys_priority));
|
||||
ntohs(member->partner.sys_priority));
|
||||
ds_put_format(ds, " partner port_id: %u\n",
|
||||
ntohs(slave->partner.port_id));
|
||||
ntohs(member->partner.port_id));
|
||||
ds_put_format(ds, " partner port_priority: %u\n",
|
||||
ntohs(slave->partner.port_priority));
|
||||
ntohs(member->partner.port_priority));
|
||||
ds_put_format(ds, " partner key: %u\n",
|
||||
ntohs(slave->partner.key));
|
||||
ntohs(member->partner.key));
|
||||
ds_put_cstr(ds, " partner state:");
|
||||
ds_put_lacp_state(ds, slave->partner.state);
|
||||
ds_put_lacp_state(ds, member->partner.state);
|
||||
ds_put_cstr(ds, "\n");
|
||||
}
|
||||
|
||||
shash_destroy(&slave_shash);
|
||||
free(sorted_slaves);
|
||||
shash_destroy(&member_shash);
|
||||
free(sorted_members);
|
||||
}
|
||||
|
||||
static void
|
||||
lacp_print_stats(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
|
||||
{
|
||||
struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
|
||||
const struct shash_node **sorted_slaves = NULL;
|
||||
struct shash member_shash = SHASH_INITIALIZER(&member_shash);
|
||||
const struct shash_node **sorted_members = NULL;
|
||||
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
int i;
|
||||
|
||||
ds_put_format(ds, "---- %s statistics ----\n", lacp->name);
|
||||
|
||||
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
|
||||
shash_add(&slave_shash, slave->name, slave);
|
||||
HMAP_FOR_EACH (member, node, &lacp->members) {
|
||||
shash_add(&member_shash, member->name, member);
|
||||
}
|
||||
sorted_slaves = shash_sort(&slave_shash);
|
||||
sorted_members = shash_sort(&member_shash);
|
||||
|
||||
for (i = 0; i < shash_count(&slave_shash); i++) {
|
||||
slave = sorted_slaves[i]->data;
|
||||
ds_put_format(ds, "\nslave: %s:\n", slave->name);
|
||||
ds_put_format(ds, " TX PDUs: %u\n", slave->count_tx_pdus);
|
||||
ds_put_format(ds, " RX PDUs: %u\n", slave->count_rx_pdus);
|
||||
ds_put_format(ds, " RX Bad PDUs: %u\n", slave->count_rx_pdus_bad);
|
||||
for (i = 0; i < shash_count(&member_shash); i++) {
|
||||
member = sorted_members[i]->data;
|
||||
ds_put_format(ds, "\nmember: %s:\n", member->name);
|
||||
ds_put_format(ds, " TX PDUs: %u\n", member->count_tx_pdus);
|
||||
ds_put_format(ds, " RX PDUs: %u\n", member->count_rx_pdus);
|
||||
ds_put_format(ds, " RX Bad PDUs: %u\n", member->count_rx_pdus_bad);
|
||||
ds_put_format(ds, " RX Marker Request PDUs: %u\n",
|
||||
slave->count_rx_pdus_marker);
|
||||
member->count_rx_pdus_marker);
|
||||
ds_put_format(ds, " Link Expired: %u\n",
|
||||
slave->count_link_expired);
|
||||
member->count_link_expired);
|
||||
ds_put_format(ds, " Link Defaulted: %u\n",
|
||||
slave->count_link_defaulted);
|
||||
member->count_link_defaulted);
|
||||
ds_put_format(ds, " Carrier Status Changed: %u\n",
|
||||
slave->count_carrier_changed);
|
||||
member->count_carrier_changed);
|
||||
}
|
||||
|
||||
shash_destroy(&slave_shash);
|
||||
free(sorted_slaves);
|
||||
shash_destroy(&member_shash);
|
||||
free(sorted_members);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1152,27 +1156,28 @@ out:
|
||||
lacp_unlock();
|
||||
}
|
||||
|
||||
/* Extract a snapshot of the current state and counters for a slave port.
|
||||
Return false if the slave is not active. */
|
||||
/* Extract a snapshot of the current state and counters for a member port.
|
||||
Return false if the member is not active. */
|
||||
bool
|
||||
lacp_get_slave_stats(const struct lacp *lacp, const void *slave_, struct lacp_slave_stats *stats)
|
||||
lacp_get_member_stats(const struct lacp *lacp, const void *member_,
|
||||
struct lacp_member_stats *stats)
|
||||
OVS_EXCLUDED(mutex)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
struct lacp_info actor;
|
||||
bool ret;
|
||||
|
||||
ovs_mutex_lock(&mutex);
|
||||
|
||||
slave = slave_lookup(lacp, slave_);
|
||||
if (slave) {
|
||||
member = member_lookup(lacp, member_);
|
||||
if (member) {
|
||||
ret = true;
|
||||
slave_get_actor(slave, &actor);
|
||||
member_get_actor(member, &actor);
|
||||
stats->dot3adAggPortActorSystemID = actor.sys_id;
|
||||
stats->dot3adAggPortPartnerOperSystemID = slave->partner.sys_id;
|
||||
stats->dot3adAggPortAttachedAggID = (lacp->key_slave->key ?
|
||||
lacp->key_slave->key :
|
||||
lacp->key_slave->port_id);
|
||||
stats->dot3adAggPortPartnerOperSystemID = member->partner.sys_id;
|
||||
stats->dot3adAggPortAttachedAggID = (lacp->key_member->key ?
|
||||
lacp->key_member->key :
|
||||
lacp->key_member->port_id);
|
||||
|
||||
/* Construct my admin-state. Assume aggregation is configured on. */
|
||||
stats->dot3adAggPortActorAdminState = LACP_STATE_AGG;
|
||||
@ -1189,12 +1194,12 @@ lacp_get_slave_stats(const struct lacp *lacp, const void *slave_, struct lacp_sl
|
||||
stats->dot3adAggPortPartnerAdminState = 0;
|
||||
|
||||
stats->dot3adAggPortActorOperState = actor.state;
|
||||
stats->dot3adAggPortPartnerOperState = slave->partner.state;
|
||||
stats->dot3adAggPortPartnerOperState = member->partner.state;
|
||||
|
||||
/* Read out the latest counters */
|
||||
stats->dot3adAggPortStatsLACPDUsRx = slave->count_rx_pdus;
|
||||
stats->dot3adAggPortStatsIllegalRx = slave->count_rx_pdus_bad;
|
||||
stats->dot3adAggPortStatsLACPDUsTx = slave->count_tx_pdus;
|
||||
stats->dot3adAggPortStatsLACPDUsRx = member->count_rx_pdus;
|
||||
stats->dot3adAggPortStatsIllegalRx = member->count_rx_pdus_bad;
|
||||
stats->dot3adAggPortStatsLACPDUsTx = member->count_tx_pdus;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
|
23
lib/lacp.h
23
lib/lacp.h
@ -46,32 +46,32 @@ struct lacp *lacp_ref(const struct lacp *);
|
||||
void lacp_configure(struct lacp *, const struct lacp_settings *);
|
||||
bool lacp_is_active(const struct lacp *);
|
||||
|
||||
bool lacp_process_packet(struct lacp *, const void *slave,
|
||||
bool lacp_process_packet(struct lacp *, const void *member,
|
||||
const struct dp_packet *packet);
|
||||
enum lacp_status lacp_status(const struct lacp *);
|
||||
|
||||
struct lacp_slave_settings {
|
||||
struct lacp_member_settings {
|
||||
char *name; /* Name (for debugging). */
|
||||
uint16_t id; /* Port ID. */
|
||||
uint16_t priority; /* Port priority. */
|
||||
uint16_t key; /* Aggregation key. */
|
||||
};
|
||||
|
||||
void lacp_slave_register(struct lacp *, void *slave_,
|
||||
const struct lacp_slave_settings *);
|
||||
void lacp_slave_unregister(struct lacp *, const void *slave);
|
||||
void lacp_slave_carrier_changed(const struct lacp *, const void *slave,
|
||||
void lacp_member_register(struct lacp *, void *member_,
|
||||
const struct lacp_member_settings *);
|
||||
void lacp_member_unregister(struct lacp *, const void *member);
|
||||
void lacp_member_carrier_changed(const struct lacp *, const void *member,
|
||||
bool carrier_up);
|
||||
bool lacp_slave_may_enable(const struct lacp *, const void *slave);
|
||||
bool lacp_slave_is_current(const struct lacp *, const void *slave_);
|
||||
bool lacp_member_may_enable(const struct lacp *, const void *member);
|
||||
bool lacp_member_is_current(const struct lacp *, const void *member_);
|
||||
|
||||
/* Callback function for lacp_run() for sending a LACP PDU. */
|
||||
typedef void lacp_send_pdu(void *slave, const void *pdu, size_t pdu_size);
|
||||
typedef void lacp_send_pdu(void *member, const void *pdu, size_t pdu_size);
|
||||
|
||||
void lacp_run(struct lacp *, lacp_send_pdu *);
|
||||
void lacp_wait(struct lacp *);
|
||||
|
||||
struct lacp_slave_stats {
|
||||
struct lacp_member_stats {
|
||||
/* id */
|
||||
struct eth_addr dot3adAggPortActorSystemID;
|
||||
struct eth_addr dot3adAggPortPartnerOperSystemID;
|
||||
@ -92,6 +92,7 @@ struct lacp_slave_stats {
|
||||
/* uint32_t dot3adAggPortStatsMarkerResponsePDUsTx; */
|
||||
};
|
||||
|
||||
bool lacp_get_slave_stats(const struct lacp *, const void *slave_, struct lacp_slave_stats *);
|
||||
bool lacp_get_member_stats(const struct lacp *, const void *member_,
|
||||
struct lacp_member_stats *);
|
||||
|
||||
#endif /* lacp.h */
|
||||
|
@ -218,13 +218,13 @@
|
||||
#define LLDPD_MODE_MAX LLDPD_MODE_FDP
|
||||
|
||||
|
||||
/* Bond slave src mac type constants */
|
||||
#define LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN 0
|
||||
#define LLDP_BOND_SLAVE_SRC_MAC_TYPE_REAL 1
|
||||
#define LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO 2
|
||||
#define LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED 3
|
||||
#define LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED 4
|
||||
#define LLDP_BOND_SLAVE_SRC_MAC_TYPE_MAX \
|
||||
LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED
|
||||
/* Bond member src mac type constants */
|
||||
#define LLDP_BOND_MEMBER_SRC_MAC_TYPE_UNKNOWN 0
|
||||
#define LLDP_BOND_MEMBER_SRC_MAC_TYPE_REAL 1
|
||||
#define LLDP_BOND_MEMBER_SRC_MAC_TYPE_ZERO 2
|
||||
#define LLDP_BOND_MEMBER_SRC_MAC_TYPE_FIXED 3
|
||||
#define LLDP_BOND_MEMBER_SRC_MAC_TYPE_LOCALLY_ADMINISTERED 4
|
||||
#define LLDP_BOND_MEMBER_SRC_MAC_TYPE_MAX \
|
||||
LLDP_BOND_MEMBER_SRC_MAC_TYPE_LOCALLY_ADMINISTERED
|
||||
|
||||
#endif /* _LLDP_H */
|
||||
|
@ -135,8 +135,8 @@ struct lldpd_config {
|
||||
int c_set_ifdescr; /* Set interface description */
|
||||
int c_promisc; /* Interfaces should be in promiscuous mode */
|
||||
int c_tx_hold; /* Transmit hold */
|
||||
int c_bond_slave_src_mac_type; /* Src mac type in lldp frames over bond
|
||||
* slaves */
|
||||
int c_bond_member_src_mac_type; /* Src mac type in lldp frames over bond
|
||||
* member interfaces */
|
||||
int c_lldp_portid_type; /* The PortID type */
|
||||
};
|
||||
|
||||
@ -158,9 +158,9 @@ struct lldpd_ops {
|
||||
};
|
||||
|
||||
/* An interface is uniquely identified by h_ifindex, h_ifname and h_ops. This
|
||||
* means if an interface becomes enslaved, it will be considered as a new
|
||||
* interface. The same applies for renaming and we include the index in case of
|
||||
* renaming to an existing interface.
|
||||
* means if an interface becomes a bond member, it will be considered as a
|
||||
* new interface. The same applies for renaming and we include the index in
|
||||
* case of renaming to an existing interface.
|
||||
*/
|
||||
struct lldpd_hardware {
|
||||
struct ovs_list h_entries;
|
||||
|
@ -384,7 +384,7 @@ is_mac_learning_update_needed(const struct mac_learning *ml,
|
||||
|
||||
if (is_gratuitous_arp) {
|
||||
/* We don't want to learn from gratuitous ARP packets that are
|
||||
* reflected back over bond slaves so we lock the learning table. For
|
||||
* reflected back over bond members so we lock the learning table. For
|
||||
* more detail, see the bigger comment in update_learning_table__(). */
|
||||
if (!is_bond) {
|
||||
return true; /* Need to set the gratuitous ARP lock. */
|
||||
@ -424,7 +424,7 @@ update_learning_table__(struct mac_learning *ml, struct eth_addr src,
|
||||
mac = mac_learning_insert(ml, src, vlan);
|
||||
if (is_gratuitous_arp) {
|
||||
/* Gratuitous ARP packets received over non-bond interfaces could be
|
||||
* reflected back over bond slaves. We don't want to learn from these
|
||||
* reflected back over bond members. We don't want to learn from these
|
||||
* reflected packets, so we lock each entry for which a gratuitous ARP
|
||||
* packet was received over a non-bond interface and refrain from
|
||||
* learning from gratuitous ARP packets that arrive over bond
|
||||
|
@ -95,7 +95,7 @@ struct mac_learning;
|
||||
#define MAC_ENTRY_DEFAULT_IDLE_TIME 300
|
||||
|
||||
/* Time, in seconds, to lock an entry updated by a gratuitous ARP to avoid
|
||||
* relearning based on a reflection from a bond slave. */
|
||||
* relearning based on a reflection from a bond member. */
|
||||
#define MAC_GRAT_ARP_LOCK_TIME 5
|
||||
|
||||
/* A MAC learning table entry.
|
||||
|
@ -257,15 +257,15 @@ enum {
|
||||
IOV_AUXBUF = 1,
|
||||
};
|
||||
|
||||
struct linux_lag_slave {
|
||||
struct linux_lag_member {
|
||||
uint32_t block_id;
|
||||
struct shash_node *node;
|
||||
};
|
||||
|
||||
/* Protects 'lag_shash' and the mutable members of struct linux_lag_slave. */
|
||||
/* Protects 'lag_shash' and the mutable members of struct linux_lag_member. */
|
||||
static struct ovs_mutex lag_mutex = OVS_MUTEX_INITIALIZER;
|
||||
|
||||
/* All slaves whose LAG masters are network devices in OvS. */
|
||||
/* All members whose LAG primary interfaces are OVS network devices. */
|
||||
static struct shash lag_shash OVS_GUARDED_BY(lag_mutex)
|
||||
= SHASH_INITIALIZER(&lag_shash);
|
||||
|
||||
@ -661,9 +661,9 @@ static void
|
||||
netdev_linux_update_lag(struct rtnetlink_change *change)
|
||||
OVS_REQUIRES(lag_mutex)
|
||||
{
|
||||
struct linux_lag_slave *lag;
|
||||
struct linux_lag_member *lag;
|
||||
|
||||
if (change->slave && netdev_linux_kind_is_lag(change->slave)) {
|
||||
if (change->sub && netdev_linux_kind_is_lag(change->sub)) {
|
||||
lag = shash_find_data(&lag_shash, change->ifname);
|
||||
|
||||
if (!lag) {
|
||||
@ -691,12 +691,12 @@ netdev_linux_update_lag(struct rtnetlink_change *change)
|
||||
|
||||
/* delete ingress block in case it exists */
|
||||
tc_add_del_qdisc(change->if_index, false, 0, TC_INGRESS);
|
||||
/* LAG master is linux netdev so add slave to same block. */
|
||||
/* LAG master is linux netdev so add member to same block. */
|
||||
error = tc_add_del_qdisc(change->if_index, true, block_id,
|
||||
TC_INGRESS);
|
||||
if (error) {
|
||||
VLOG_WARN("failed to bind LAG slave %s to master's block",
|
||||
change->ifname);
|
||||
VLOG_WARN("failed to bind LAG member %s to "
|
||||
"primary's block", change->ifname);
|
||||
shash_delete(&lag_shash, lag->node);
|
||||
free(lag);
|
||||
}
|
||||
@ -705,7 +705,7 @@ netdev_linux_update_lag(struct rtnetlink_change *change)
|
||||
netdev_close(master_netdev);
|
||||
}
|
||||
} else if (change->master_ifindex == 0) {
|
||||
/* Check if this was a lag slave that has been freed. */
|
||||
/* Check if this was a lag member that has been removed. */
|
||||
lag = shash_find_data(&lag_shash, change->ifname);
|
||||
|
||||
if (lag) {
|
||||
@ -860,7 +860,7 @@ netdev_linux_update__(struct netdev_linux *dev,
|
||||
rtnetlink_report_link();
|
||||
}
|
||||
|
||||
if (change->master && netdev_linux_kind_is_lag(change->master)) {
|
||||
if (change->primary && netdev_linux_kind_is_lag(change->primary)) {
|
||||
dev->is_lag_master = true;
|
||||
}
|
||||
|
||||
@ -6376,7 +6376,7 @@ netdev_linux_update_via_netlink(struct netdev_linux *netdev)
|
||||
netdev->get_ifindex_error = 0;
|
||||
changed = true;
|
||||
}
|
||||
if (change->master && netdev_linux_kind_is_lag(change->master)) {
|
||||
if (change->primary && netdev_linux_kind_is_lag(change->primary)) {
|
||||
netdev->is_lag_master = true;
|
||||
}
|
||||
if (changed) {
|
||||
|
@ -1334,39 +1334,39 @@ check_OUTPUT_REG(const struct ofpact_output_reg *a,
|
||||
|
||||
/* Action structure for NXAST_BUNDLE and NXAST_BUNDLE_LOAD.
|
||||
*
|
||||
* The bundle actions choose a slave from a supplied list of options.
|
||||
* The bundle actions choose a member from a supplied list of options.
|
||||
* NXAST_BUNDLE outputs to its selection. NXAST_BUNDLE_LOAD writes its
|
||||
* selection to a register.
|
||||
*
|
||||
* The list of possible slaves follows the nx_action_bundle structure. The size
|
||||
* of each slave is governed by its type as indicated by the 'slave_type'
|
||||
* parameter. The list of slaves should be padded at its end with zeros to make
|
||||
* the total length of the action a multiple of 8.
|
||||
* The list of possible members follows the nx_action_bundle structure. The
|
||||
* size of each member is governed by its type as indicated by the
|
||||
* 'member_type' parameter. The list of members should be padded at its end
|
||||
* with zeros to make the total length of the action a multiple of 8.
|
||||
*
|
||||
* Switches infer from the 'slave_type' parameter the size of each slave. All
|
||||
* implementations must support the NXM_OF_IN_PORT 'slave_type' which indicates
|
||||
* that the slaves are OpenFlow port numbers with NXM_LENGTH(NXM_OF_IN_PORT) ==
|
||||
* 2 byte width. Switches should reject actions which indicate unknown or
|
||||
* unsupported slave types.
|
||||
* Switches infer from the 'member_type' parameter the size of each member.
|
||||
* All implementations must support the NXM_OF_IN_PORT 'member_type' which
|
||||
* indicates that the members are OpenFlow port numbers with
|
||||
* NXM_LENGTH(NXM_OF_IN_PORT) == 2 byte width. Switches should reject actions
|
||||
* which indicate unknown or unsupported member types.
|
||||
*
|
||||
* Switches use a strategy dictated by the 'algorithm' parameter to choose a
|
||||
* slave. If the switch does not support the specified 'algorithm' parameter,
|
||||
* member. If the switch does not support the specified 'algorithm' parameter,
|
||||
* it should reject the action.
|
||||
*
|
||||
* Several algorithms take into account liveness when selecting slaves. The
|
||||
* liveness of a slave is implementation defined (with one exception), but will
|
||||
* generally take into account things like its carrier status and the results
|
||||
* of any link monitoring protocols which happen to be running on it. In order
|
||||
* to give controllers a place-holder value, the OFPP_NONE port is always
|
||||
* considered live, that is, NXAST_BUNDLE_LOAD stores OFPP_NONE in the output
|
||||
* register if no slave is live.
|
||||
* Several algorithms take into account liveness when selecting members. The
|
||||
* liveness of a member is implementation defined (with one exception), but
|
||||
* will generally take into account things like its carrier status and the
|
||||
* results of any link monitoring protocols which happen to be running on it.
|
||||
* In order to give controllers a place-holder value, the OFPP_NONE port is
|
||||
* always considered live, that is, NXAST_BUNDLE_LOAD stores OFPP_NONE in the
|
||||
* output register if no member is live.
|
||||
*
|
||||
* Some slave selection strategies require the use of a hash function, in which
|
||||
* case the 'fields' and 'basis' parameters should be populated. The 'fields'
|
||||
* parameter (one of NX_HASH_FIELDS_*) designates which parts of the flow to
|
||||
* hash. Refer to the definition of "enum nx_hash_fields" for details. The
|
||||
* 'basis' parameter is used as a universal hash parameter. Different values
|
||||
* of 'basis' yield different hash results.
|
||||
* Some member selection strategies require the use of a hash function, in
|
||||
* which case the 'fields' and 'basis' parameters should be populated. The
|
||||
* 'fields' parameter (one of NX_HASH_FIELDS_*) designates which parts of the
|
||||
* flow to hash. Refer to the definition of "enum nx_hash_fields" for details.
|
||||
* The 'basis' parameter is used as a universal hash parameter. Different
|
||||
* values of 'basis' yield different hash results.
|
||||
*
|
||||
* The 'zero' parameter at the end of the action structure is reserved for
|
||||
* future use. Switches are required to reject actions which have nonzero
|
||||
@ -1375,24 +1375,24 @@ check_OUTPUT_REG(const struct ofpact_output_reg *a,
|
||||
* NXAST_BUNDLE actions should have 'ofs_nbits' and 'dst' zeroed. Switches
|
||||
* should reject actions which have nonzero bytes in either of these fields.
|
||||
*
|
||||
* NXAST_BUNDLE_LOAD stores the OpenFlow port number of the selected slave in
|
||||
* NXAST_BUNDLE_LOAD stores the OpenFlow port number of the selected member in
|
||||
* dst[ofs:ofs+n_bits]. The format and semantics of 'dst' and 'ofs_nbits' are
|
||||
* similar to those for the NXAST_REG_LOAD action. */
|
||||
struct nx_action_bundle {
|
||||
ovs_be16 type; /* OFPAT_VENDOR. */
|
||||
ovs_be16 len; /* Length including slaves. */
|
||||
ovs_be16 len; /* Length including members. */
|
||||
ovs_be32 vendor; /* NX_VENDOR_ID. */
|
||||
ovs_be16 subtype; /* NXAST_BUNDLE or NXAST_BUNDLE_LOAD. */
|
||||
|
||||
/* Slave choice algorithm to apply to hash value. */
|
||||
/* Member choice algorithm to apply to hash value. */
|
||||
ovs_be16 algorithm; /* One of NX_BD_ALG_*. */
|
||||
|
||||
/* What fields to hash and how. */
|
||||
ovs_be16 fields; /* One of NX_HASH_FIELDS_*. */
|
||||
ovs_be16 basis; /* Universal hash parameter. */
|
||||
|
||||
ovs_be32 slave_type; /* NXM_OF_IN_PORT. */
|
||||
ovs_be16 n_slaves; /* Number of slaves. */
|
||||
ovs_be32 member_type; /* NXM_OF_IN_PORT. */
|
||||
ovs_be16 n_members; /* Number of members. */
|
||||
|
||||
ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */
|
||||
ovs_be32 dst; /* Destination. */
|
||||
@ -1408,29 +1408,29 @@ decode_bundle(bool load, const struct nx_action_bundle *nab,
|
||||
{
|
||||
static struct vlog_rate_limit rll = VLOG_RATE_LIMIT_INIT(1, 5);
|
||||
struct ofpact_bundle *bundle;
|
||||
uint32_t slave_type;
|
||||
size_t slaves_size, i;
|
||||
uint32_t member_type;
|
||||
size_t members_size, i;
|
||||
enum ofperr error;
|
||||
|
||||
bundle = ofpact_put_BUNDLE(ofpacts);
|
||||
|
||||
bundle->n_slaves = ntohs(nab->n_slaves);
|
||||
bundle->n_members = ntohs(nab->n_members);
|
||||
bundle->basis = ntohs(nab->basis);
|
||||
bundle->fields = ntohs(nab->fields);
|
||||
bundle->algorithm = ntohs(nab->algorithm);
|
||||
slave_type = ntohl(nab->slave_type);
|
||||
slaves_size = ntohs(nab->len) - sizeof *nab;
|
||||
member_type = ntohl(nab->member_type);
|
||||
members_size = ntohs(nab->len) - sizeof *nab;
|
||||
|
||||
error = OFPERR_OFPBAC_BAD_ARGUMENT;
|
||||
if (!flow_hash_fields_valid(bundle->fields)) {
|
||||
VLOG_WARN_RL(&rll, "unsupported fields %d", (int) bundle->fields);
|
||||
} else if (bundle->n_slaves > BUNDLE_MAX_SLAVES) {
|
||||
VLOG_WARN_RL(&rll, "too many slaves");
|
||||
} else if (bundle->n_members > BUNDLE_MAX_MEMBERS) {
|
||||
VLOG_WARN_RL(&rll, "too many members");
|
||||
} else if (bundle->algorithm != NX_BD_ALG_HRW
|
||||
&& bundle->algorithm != NX_BD_ALG_ACTIVE_BACKUP) {
|
||||
VLOG_WARN_RL(&rll, "unsupported algorithm %d", (int) bundle->algorithm);
|
||||
} else if (slave_type != mf_nxm_header(MFF_IN_PORT)) {
|
||||
VLOG_WARN_RL(&rll, "unsupported slave type %"PRIu32, slave_type);
|
||||
} else if (member_type != mf_nxm_header(MFF_IN_PORT)) {
|
||||
VLOG_WARN_RL(&rll, "unsupported member type %"PRIu32, member_type);
|
||||
} else {
|
||||
error = 0;
|
||||
}
|
||||
@ -1461,15 +1461,15 @@ decode_bundle(bool load, const struct nx_action_bundle *nab,
|
||||
}
|
||||
}
|
||||
|
||||
if (slaves_size < bundle->n_slaves * sizeof(ovs_be16)) {
|
||||
if (members_size < bundle->n_members * sizeof(ovs_be16)) {
|
||||
VLOG_WARN_RL(&rll, "Nicira action %s only has %"PRIuSIZE" bytes "
|
||||
"allocated for slaves. %"PRIuSIZE" bytes are required "
|
||||
"for %u slaves.",
|
||||
load ? "bundle_load" : "bundle", slaves_size,
|
||||
bundle->n_slaves * sizeof(ovs_be16), bundle->n_slaves);
|
||||
"allocated for members. %"PRIuSIZE" bytes are "
|
||||
"required for %u members.",
|
||||
load ? "bundle_load" : "bundle", members_size,
|
||||
bundle->n_members * sizeof(ovs_be16), bundle->n_members);
|
||||
error = OFPERR_OFPBAC_BAD_LEN;
|
||||
} else {
|
||||
for (i = 0; i < bundle->n_slaves; i++) {
|
||||
for (i = 0; i < bundle->n_members; i++) {
|
||||
ofp_port_t ofp_port
|
||||
= u16_to_ofp(ntohs(((ovs_be16 *)(nab + 1))[i]));
|
||||
ofpbuf_put(ofpacts, &ofp_port, sizeof ofp_port);
|
||||
@ -1506,29 +1506,29 @@ encode_BUNDLE(const struct ofpact_bundle *bundle,
|
||||
enum ofp_version ofp_version OVS_UNUSED,
|
||||
struct ofpbuf *out)
|
||||
{
|
||||
int slaves_len = ROUND_UP(2 * bundle->n_slaves, OFP_ACTION_ALIGN);
|
||||
int members_len = ROUND_UP(2 * bundle->n_members, OFP_ACTION_ALIGN);
|
||||
struct nx_action_bundle *nab;
|
||||
ovs_be16 *slaves;
|
||||
ovs_be16 *members;
|
||||
size_t i;
|
||||
|
||||
nab = (bundle->dst.field
|
||||
? put_NXAST_BUNDLE_LOAD(out)
|
||||
: put_NXAST_BUNDLE(out));
|
||||
nab->len = htons(ntohs(nab->len) + slaves_len);
|
||||
nab->len = htons(ntohs(nab->len) + members_len);
|
||||
nab->algorithm = htons(bundle->algorithm);
|
||||
nab->fields = htons(bundle->fields);
|
||||
nab->basis = htons(bundle->basis);
|
||||
nab->slave_type = htonl(mf_nxm_header(MFF_IN_PORT));
|
||||
nab->n_slaves = htons(bundle->n_slaves);
|
||||
nab->member_type = htonl(mf_nxm_header(MFF_IN_PORT));
|
||||
nab->n_members = htons(bundle->n_members);
|
||||
if (bundle->dst.field) {
|
||||
nab->ofs_nbits = nxm_encode_ofs_nbits(bundle->dst.ofs,
|
||||
bundle->dst.n_bits);
|
||||
nab->dst = htonl(nxm_header_from_mff(bundle->dst.field));
|
||||
}
|
||||
|
||||
slaves = ofpbuf_put_zeros(out, slaves_len);
|
||||
for (i = 0; i < bundle->n_slaves; i++) {
|
||||
slaves[i] = htons(ofp_to_u16(bundle->slaves[i]));
|
||||
members = ofpbuf_put_zeros(out, members_len);
|
||||
for (i = 0; i < bundle->n_members; i++) {
|
||||
members[i] = htons(ofp_to_u16(bundle->members[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3585,7 +3585,7 @@ check_STACK_POP(const struct ofpact_stack *a,
|
||||
*/
|
||||
struct nx_action_cnt_ids {
|
||||
ovs_be16 type; /* OFPAT_VENDOR. */
|
||||
ovs_be16 len; /* Length including slaves. */
|
||||
ovs_be16 len; /* Length including cnt_ids. */
|
||||
ovs_be32 vendor; /* NX_VENDOR_ID. */
|
||||
ovs_be16 subtype; /* NXAST_DEC_TTL_CNT_IDS. */
|
||||
|
||||
|
@ -789,15 +789,16 @@ $ ovs-ofctl -O OpenFlow10 add-flow br0 actions=mod_nw_src:1.2.3.4
|
||||
|
||||
<action name="BUNDLE,BUNDLE_LOAD">
|
||||
<h2>The <code>bundle</code> and <code>bundle_load</code> actions</h2>
|
||||
<syntax><code>bundle(</code><var>fields</var><code>, </code><var>basis</var><code>, </code><var>algorithm</var><code>, ofport, slaves:</code><var>port</var>...<code>)</code></syntax>
|
||||
<syntax><code>bundle_load(</code><var>fields</var><code>, </code><var>basis</var><code>, </code><var>algorithm</var><code>, ofport, </code><var>dst</var><code>, slaves:</code><var>port</var>...<code>)</code></syntax>
|
||||
<syntax><code>bundle(</code><var>fields</var><code>, </code><var>basis</var><code>, </code><var>algorithm</var><code>, ofport, members:</code><var>port</var>...<code>)</code></syntax>
|
||||
<syntax><code>bundle_load(</code><var>fields</var><code>, </code><var>basis</var><code>, </code><var>algorithm</var><code>, ofport, </code><var>dst</var><code>, members:</code><var>port</var>...<code>)</code></syntax>
|
||||
|
||||
<p>
|
||||
These actions choose a port (``slave'') from a comma-separated OpenFlow
|
||||
<var>port</var> list. After selecting the port, <code>bundle</code>
|
||||
outputs to it, whereas <code>bundle_load</code> writes its port number
|
||||
to <var>dst</var>, which must be a 16-bit or wider field or subfield in
|
||||
the syntax described under ``Field Specifications'' above.
|
||||
These actions choose a port (a ``member'') from a
|
||||
comma-separated OpenFlow <var>port</var> list. After selecting the
|
||||
port, <code>bundle</code> outputs to it, whereas
|
||||
<code>bundle_load</code> writes its port number to <var>dst</var>,
|
||||
which must be a 16-bit or wider field or subfield in the syntax
|
||||
described under ``Field Specifications'' above.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@ -854,20 +855,20 @@ $ ovs-ofctl -O OpenFlow10 add-flow br0 actions=mod_nw_src:1.2.3.4
|
||||
<dl>
|
||||
<dt><code>active_backup</code></dt>
|
||||
<dd>
|
||||
Chooses the first live port listed in <var>slaves</var>.
|
||||
Chooses the first live port listed in <var>members</var>.
|
||||
</dd>
|
||||
|
||||
<dt><code>hrw</code> (Highest Random Weight)</dt>
|
||||
<dd>
|
||||
<p>
|
||||
Computes the following, considering only the live ports in
|
||||
<var>slaves</var>:
|
||||
<var>members</var>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for <var>i</var> in [1,<var>n_slaves</var>]:
|
||||
for <var>i</var> in [1,<var>n_members</var>]:
|
||||
<var>weights</var>[<var>i</var>] = hash(<var>flow</var>, <var>i</var>)
|
||||
<var>slave</var> = { <var>i</var> such that <var>weights</var>[<var>i</var>] >= <var>weights</var>[<var>j</var>] for all <var>j</var> != <var>i</var> }
|
||||
<var>member</var> = { <var>i</var> such that <var>weights</var>[<var>i</var>] >= <var>weights</var>[<var>j</var>] for all <var>j</var> != <var>i</var> }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@ -877,17 +878,17 @@ for <var>i</var> in [1,<var>n_slaves</var>]:
|
||||
</dl>
|
||||
|
||||
<p>
|
||||
The algorithms take port liveness into account when selecting slaves.
|
||||
The definition of whether a port is live is subject to change. It
|
||||
currently takes into account carrier status and link monitoring
|
||||
protocols such as BFD and CFM. If none of the slaves is live,
|
||||
<code>bundle</code> does not output the packet and
|
||||
The algorithms take port liveness into account when selecting
|
||||
members. The definition of whether a port is live is subject to
|
||||
change. It currently takes into account carrier status and link
|
||||
monitoring protocols such as BFD and CFM. If none of the members is
|
||||
live, <code>bundle</code> does not output the packet and
|
||||
<code>bundle_load</code> stores <code>OFPP_NONE</code> (65535) in the
|
||||
output field.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Example: <code>bundle(eth_src,0,hrw,ofport,slaves:4,8)</code> uses an
|
||||
Example: <code>bundle(eth_src,0,hrw,ofport,members:4,8)</code> uses an
|
||||
Ethernet source hash with basis 0, to select between OpenFlow ports 4
|
||||
and 8 using the Highest Random Weight algorithm.
|
||||
</p>
|
||||
|
@ -68,10 +68,10 @@ rtnetlink_parse_link_info(const struct nlattr *nla,
|
||||
ARRAY_SIZE(linkinfo_policy));
|
||||
|
||||
if (parsed) {
|
||||
change->master = (linkinfo[IFLA_INFO_KIND]
|
||||
change->primary = (linkinfo[IFLA_INFO_KIND]
|
||||
? nl_attr_get_string(linkinfo[IFLA_INFO_KIND])
|
||||
: NULL);
|
||||
change->slave = (linkinfo[IFLA_INFO_SLAVE_KIND]
|
||||
change->sub = (linkinfo[IFLA_INFO_SLAVE_KIND]
|
||||
? nl_attr_get_string(linkinfo[IFLA_INFO_SLAVE_KIND])
|
||||
: NULL);
|
||||
}
|
||||
@ -134,8 +134,8 @@ rtnetlink_parse(struct ofpbuf *buf, struct rtnetlink_change *change)
|
||||
parsed = rtnetlink_parse_link_info(attrs[IFLA_LINKINFO],
|
||||
change);
|
||||
} else {
|
||||
change->master = NULL;
|
||||
change->slave = NULL;
|
||||
change->primary = NULL;
|
||||
change->sub = NULL;
|
||||
}
|
||||
}
|
||||
} else if (rtnetlink_type_is_rtnlgrp_addr(nlmsg->nlmsg_type)) {
|
||||
|
@ -49,9 +49,9 @@ struct rtnetlink_change {
|
||||
/* Network device address status. */
|
||||
/* xxx To be added when needed. */
|
||||
|
||||
/* Link info. */
|
||||
const char *master; /* Kind of master (NULL if not master). */
|
||||
const char *slave; /* Kind of slave (NULL if not slave). */
|
||||
/* Link bonding info. */
|
||||
const char *primary; /* Kind of primary (NULL if not primary). */
|
||||
const char *sub; /* Kind of subordinate (NULL if not sub). */
|
||||
};
|
||||
|
||||
/* Function called to report that a netdev has changed. 'change' describes the
|
||||
|
@ -77,8 +77,10 @@ unixctl_list_commands(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
||||
const struct shash_node *node = nodes[i];
|
||||
const struct unixctl_command *command = node->data;
|
||||
|
||||
if (command->usage) {
|
||||
ds_put_format(&ds, " %-23s %s\n", node->name, command->usage);
|
||||
}
|
||||
}
|
||||
free(nodes);
|
||||
|
||||
unixctl_command_reply(conn, ds_cstr(&ds));
|
||||
@ -94,7 +96,7 @@ unixctl_version(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
||||
|
||||
/* Registers a unixctl command with the given 'name'. 'usage' describes the
|
||||
* arguments to the command; it is used only for presentation to the user in
|
||||
* "list-commands" output.
|
||||
* "list-commands" output. (If 'usage' is NULL, then the command is hidden.)
|
||||
*
|
||||
* 'cb' is called when the command is received. It is passed an array
|
||||
* containing the command name and arguments, plus a copy of 'aux'. Normally
|
||||
|
815
ofproto/bond.c
815
ofproto/bond.c
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@ struct ofpbuf;
|
||||
struct ofproto_dpif;
|
||||
enum lacp_status;
|
||||
|
||||
/* How flows are balanced among bond slaves. */
|
||||
/* How flows are balanced among bond member interfaces. */
|
||||
enum bond_mode {
|
||||
BM_TCP, /* Transport Layer Load Balance. */
|
||||
BM_SLB, /* Source Load Balance. */
|
||||
@ -51,12 +51,12 @@ struct bond_settings {
|
||||
const char *primary; /* For AB mode, primary interface name. */
|
||||
|
||||
/* Link status detection. */
|
||||
int up_delay; /* ms before enabling an up slave. */
|
||||
int down_delay; /* ms before disabling a down slave. */
|
||||
int up_delay; /* ms before enabling an up member. */
|
||||
int down_delay; /* ms before disabling a down member. */
|
||||
|
||||
bool lacp_fallback_ab_cfg; /* Fallback to active-backup on LACP failure. */
|
||||
|
||||
struct eth_addr active_slave_mac;
|
||||
struct eth_addr active_member_mac;
|
||||
/* The MAC address of the interface
|
||||
that was active during the last
|
||||
ovs run. */
|
||||
@ -74,21 +74,22 @@ void bond_unref(struct bond *);
|
||||
struct bond *bond_ref(const struct bond *);
|
||||
|
||||
bool bond_reconfigure(struct bond *, const struct bond_settings *);
|
||||
void bond_slave_register(struct bond *, void *slave_, ofp_port_t ofport, struct netdev *);
|
||||
void bond_slave_set_netdev(struct bond *, void *slave_, struct netdev *);
|
||||
void bond_slave_unregister(struct bond *, const void *slave);
|
||||
void bond_member_register(struct bond *, void *member_, ofp_port_t ofport,
|
||||
struct netdev *);
|
||||
void bond_member_set_netdev(struct bond *, void *member_, struct netdev *);
|
||||
void bond_member_unregister(struct bond *, const void *member);
|
||||
|
||||
bool bond_run(struct bond *, enum lacp_status);
|
||||
void bond_wait(struct bond *);
|
||||
|
||||
void bond_slave_set_may_enable(struct bond *, void *slave_, bool may_enable);
|
||||
void bond_member_set_may_enable(struct bond *, void *member_, bool may_enable);
|
||||
|
||||
/* Special MAC learning support for SLB bonding. */
|
||||
bool bond_should_send_learning_packets(struct bond *);
|
||||
struct dp_packet *bond_compose_learning_packet(struct bond *,
|
||||
const struct eth_addr eth_src,
|
||||
uint16_t vlan, void **port_aux);
|
||||
bool bond_get_changed_active_slave(const char *name, struct eth_addr *mac,
|
||||
bool bond_get_changed_active_member(const char *name, struct eth_addr *mac,
|
||||
bool force);
|
||||
|
||||
/* Packet processing. */
|
||||
@ -97,9 +98,9 @@ enum bond_verdict {
|
||||
BV_DROP, /* Drop this packet. */
|
||||
BV_DROP_IF_MOVED /* Drop if we've learned a different port. */
|
||||
};
|
||||
enum bond_verdict bond_check_admissibility(struct bond *, const void *slave_,
|
||||
enum bond_verdict bond_check_admissibility(struct bond *, const void *member_,
|
||||
const struct eth_addr dst);
|
||||
void *bond_choose_output_slave(struct bond *, const struct flow *,
|
||||
void *bond_choose_output_member(struct bond *, const struct flow *,
|
||||
struct flow_wildcards *, uint16_t vlan);
|
||||
|
||||
/* Rebalancing. */
|
||||
@ -119,7 +120,7 @@ void bond_rebalance(struct bond *);
|
||||
*
|
||||
* On handling first output packet, 256 post recirculation flows are installed:
|
||||
*
|
||||
* recirc_id=<bond_recirc_id>, dp_hash=<[0..255]>/0xff, actions: output<slave>
|
||||
* recirc_id=<bond_recirc_id>, dp_hash=<[0..255]>/0xff, actions: output<member>
|
||||
*
|
||||
* Bond module pulls stats from those post recirculation rules. If rebalancing
|
||||
* is needed, those rules are updated with new output actions.
|
||||
|
@ -41,8 +41,8 @@ struct rule;
|
||||
*
|
||||
* Recirculation is the use of freezing to allow a frame to re-enter the
|
||||
* datapath packet processing path to achieve more flexible packet processing,
|
||||
* such as modifying header fields after MPLS POP action and selecting a slave
|
||||
* port for bond ports.
|
||||
* such as modifying header fields after MPLS POP action and selecting a
|
||||
* member interface for bond ports.
|
||||
*
|
||||
*
|
||||
* Data path and user space interface
|
||||
|
@ -305,7 +305,7 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
|
||||
SFLEthernet_counters* eth_counters;
|
||||
struct netdev_stats stats;
|
||||
enum netdev_flags flags;
|
||||
struct lacp_slave_stats lacp_stats;
|
||||
struct lacp_member_stats lacp_stats;
|
||||
const char *ifName;
|
||||
|
||||
dsp = dpif_sflow_find_port(ds, u32_to_odp(poller->bridgePort));
|
||||
|
@ -2431,7 +2431,7 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
|
||||
}
|
||||
vid = out_xvlan.v[0].vid;
|
||||
if (ovs_list_is_empty(&out_xbundle->xports)) {
|
||||
/* Partially configured bundle with no slaves. Drop the packet. */
|
||||
/* Partially configured bundle with no members. Drop the packet. */
|
||||
return;
|
||||
} else if (!out_xbundle->bond) {
|
||||
xport = CONTAINER_OF(ovs_list_front(&out_xbundle->xports), struct xport,
|
||||
@ -2456,12 +2456,12 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
|
||||
}
|
||||
}
|
||||
|
||||
ofport = bond_choose_output_slave(out_xbundle->bond,
|
||||
ofport = bond_choose_output_member(out_xbundle->bond,
|
||||
&ctx->xin->flow, wc, vid);
|
||||
xport = xport_lookup(ctx->xcfg, ofport);
|
||||
|
||||
if (!xport) {
|
||||
/* No slaves enabled, so drop packet. */
|
||||
/* No member interfaces enabled, so drop packet. */
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3379,10 +3379,10 @@ process_special(struct xlate_ctx *ctx, const struct xport *xport)
|
||||
if (packet) {
|
||||
lacp_may_enable = lacp_process_packet(xport->xbundle->lacp,
|
||||
xport->ofport, packet);
|
||||
/* Update LACP status in bond-slave to avoid packet-drops until
|
||||
* LACP state machine is run by the main thread. */
|
||||
/* Update LACP status in bond-member to avoid packet-drops
|
||||
* until LACP state machine is run by the main thread. */
|
||||
if (xport->xbundle->bond && lacp_may_enable) {
|
||||
bond_slave_set_may_enable(xport->xbundle->bond, xport->ofport,
|
||||
bond_member_set_may_enable(xport->xbundle->bond, xport->ofport,
|
||||
lacp_may_enable);
|
||||
}
|
||||
}
|
||||
@ -4210,7 +4210,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
|
||||
if (xr && bond_use_lb_output_action(xport->xbundle->bond)) {
|
||||
/*
|
||||
* If bond mode is balance-tcp and optimize balance tcp is enabled
|
||||
* then use the hash directly for slave selection and avoid
|
||||
* then use the hash directly for member selection and avoid
|
||||
* recirculation.
|
||||
*
|
||||
* Currently support for netdev datapath only.
|
||||
@ -5391,7 +5391,7 @@ xlate_set_queue_action(struct xlate_ctx *ctx, uint32_t queue_id)
|
||||
}
|
||||
|
||||
static bool
|
||||
slave_enabled_cb(ofp_port_t ofp_port, void *xbridge_)
|
||||
member_enabled_cb(ofp_port_t ofp_port, void *xbridge_)
|
||||
{
|
||||
const struct xbridge *xbridge = xbridge_;
|
||||
struct xport *port;
|
||||
@ -5420,7 +5420,7 @@ xlate_bundle_action(struct xlate_ctx *ctx,
|
||||
{
|
||||
ofp_port_t port;
|
||||
|
||||
port = bundle_execute(bundle, &ctx->xin->flow, ctx->wc, slave_enabled_cb,
|
||||
port = bundle_execute(bundle, &ctx->xin->flow, ctx->wc, member_enabled_cb,
|
||||
CONST_CAST(struct xbridge *, ctx->xbridge));
|
||||
if (bundle->dst.field) {
|
||||
nxm_reg_load(&bundle->dst, ofp_to_u16(port), &ctx->xin->flow, ctx->wc);
|
||||
|
@ -2199,7 +2199,7 @@ port_modified(struct ofport *port_)
|
||||
struct netdev *netdev = port->up.netdev;
|
||||
|
||||
if (port->bundle && port->bundle->bond) {
|
||||
bond_slave_set_netdev(port->bundle->bond, port, netdev);
|
||||
bond_member_set_netdev(port->bundle->bond, port, netdev);
|
||||
}
|
||||
|
||||
if (port->cfm) {
|
||||
@ -3140,10 +3140,10 @@ bundle_del_port(struct ofport_dpif *port)
|
||||
port->bundle = NULL;
|
||||
|
||||
if (bundle->lacp) {
|
||||
lacp_slave_unregister(bundle->lacp, port);
|
||||
lacp_member_unregister(bundle->lacp, port);
|
||||
}
|
||||
if (bundle->bond) {
|
||||
bond_slave_unregister(bundle->bond, port);
|
||||
bond_member_unregister(bundle->bond, port);
|
||||
}
|
||||
|
||||
bundle_update(bundle);
|
||||
@ -3151,7 +3151,7 @@ bundle_del_port(struct ofport_dpif *port)
|
||||
|
||||
static bool
|
||||
bundle_add_port(struct ofbundle *bundle, ofp_port_t ofp_port,
|
||||
struct lacp_slave_settings *lacp)
|
||||
struct lacp_member_settings *lacp)
|
||||
{
|
||||
struct ofport_dpif *port;
|
||||
|
||||
@ -3177,7 +3177,7 @@ bundle_add_port(struct ofbundle *bundle, ofp_port_t ofp_port,
|
||||
}
|
||||
if (lacp) {
|
||||
bundle->ofproto->backer->need_revalidate = REV_RECONFIGURE;
|
||||
lacp_slave_register(bundle->lacp, port, lacp);
|
||||
lacp_member_register(bundle->lacp, port, lacp);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -3236,8 +3236,8 @@ bundle_set(struct ofproto *ofproto_, void *aux,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ovs_assert(s->n_slaves == 1 || s->bond != NULL);
|
||||
ovs_assert((s->lacp != NULL) == (s->lacp_slaves != NULL));
|
||||
ovs_assert(s->n_members == 1 || s->bond != NULL);
|
||||
ovs_assert((s->lacp != NULL) == (s->lacp_members != NULL));
|
||||
|
||||
if (!bundle) {
|
||||
bundle = xmalloc(sizeof *bundle);
|
||||
@ -3283,18 +3283,18 @@ bundle_set(struct ofproto *ofproto_, void *aux,
|
||||
|
||||
/* Update set of ports. */
|
||||
ok = true;
|
||||
for (i = 0; i < s->n_slaves; i++) {
|
||||
if (!bundle_add_port(bundle, s->slaves[i],
|
||||
s->lacp ? &s->lacp_slaves[i] : NULL)) {
|
||||
for (i = 0; i < s->n_members; i++) {
|
||||
if (!bundle_add_port(bundle, s->members[i],
|
||||
s->lacp ? &s->lacp_members[i] : NULL)) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (!ok || ovs_list_size(&bundle->ports) != s->n_slaves) {
|
||||
if (!ok || ovs_list_size(&bundle->ports) != s->n_members) {
|
||||
struct ofport_dpif *next_port;
|
||||
|
||||
LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) {
|
||||
for (i = 0; i < s->n_slaves; i++) {
|
||||
if (s->slaves[i] == port->up.ofp_port) {
|
||||
for (i = 0; i < s->n_members; i++) {
|
||||
if (s->members[i] == port->up.ofp_port) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
@ -3303,7 +3303,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
|
||||
found: ;
|
||||
}
|
||||
}
|
||||
ovs_assert(ovs_list_size(&bundle->ports) <= s->n_slaves);
|
||||
ovs_assert(ovs_list_size(&bundle->ports) <= s->n_members);
|
||||
|
||||
if (ovs_list_is_empty(&bundle->ports)) {
|
||||
bundle_destroy(bundle);
|
||||
@ -3408,7 +3408,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
|
||||
}
|
||||
|
||||
LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
|
||||
bond_slave_register(bundle->bond, port,
|
||||
bond_member_register(bundle->bond, port,
|
||||
port->up.ofp_port, port->up.netdev);
|
||||
}
|
||||
} else {
|
||||
@ -3562,7 +3562,7 @@ bundle_run(struct ofbundle *bundle)
|
||||
struct ofport_dpif *port;
|
||||
|
||||
LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
|
||||
bond_slave_set_may_enable(bundle->bond, port, port->up.may_enable);
|
||||
bond_member_set_may_enable(bundle->bond, port, port->up.may_enable);
|
||||
}
|
||||
|
||||
if (bond_run(bundle->bond, lacp_status(bundle->lacp))) {
|
||||
@ -3808,7 +3808,7 @@ may_enable_port(struct ofport_dpif *ofport)
|
||||
|
||||
/* If LACP is enabled, it must report that the link is enabled. */
|
||||
if (ofport->bundle
|
||||
&& !lacp_slave_may_enable(ofport->bundle->lacp, ofport)) {
|
||||
&& !lacp_member_may_enable(ofport->bundle->lacp, ofport)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3824,7 +3824,7 @@ port_run(struct ofport_dpif *ofport)
|
||||
|
||||
ofport->carrier_seq = carrier_seq;
|
||||
if (carrier_changed && ofport->bundle) {
|
||||
lacp_slave_carrier_changed(ofport->bundle->lacp, ofport, enable);
|
||||
lacp_member_carrier_changed(ofport->bundle->lacp, ofport, enable);
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
@ -3936,7 +3936,7 @@ port_del(struct ofproto *ofproto_, ofp_port_t ofp_port)
|
||||
/* The caller is going to close ofport->up.netdev. If this is a
|
||||
* bonded port, then the bond is using that netdev, so remove it
|
||||
* from the bond. The client will need to reconfigure everything
|
||||
* after deleting ports, so then the slave will get re-added. */
|
||||
* after deleting ports, so then the member will get re-added. */
|
||||
bundle_remove(&ofport->up);
|
||||
}
|
||||
}
|
||||
@ -4020,11 +4020,12 @@ vport_get_status(const struct ofport *ofport_, char **errp)
|
||||
}
|
||||
|
||||
static int
|
||||
port_get_lacp_stats(const struct ofport *ofport_, struct lacp_slave_stats *stats)
|
||||
port_get_lacp_stats(const struct ofport *ofport_,
|
||||
struct lacp_member_stats *stats)
|
||||
{
|
||||
struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
|
||||
if (ofport->bundle && ofport->bundle->lacp) {
|
||||
if (lacp_get_slave_stats(ofport->bundle->lacp, ofport, stats)) {
|
||||
if (lacp_get_member_stats(ofport->bundle->lacp, ofport, stats)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -4125,7 +4126,7 @@ port_is_lacp_current(const struct ofport *ofport_)
|
||||
{
|
||||
const struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
|
||||
return (ofport->bundle && ofport->bundle->lacp
|
||||
? lacp_slave_is_current(ofport->bundle->lacp, ofport)
|
||||
? lacp_member_is_current(ofport->bundle->lacp, ofport)
|
||||
: -1);
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ int ofproto_dpif_add_internal_flow(struct ofproto_dpif *,
|
||||
int ofproto_dpif_delete_internal_flow(struct ofproto_dpif *, struct match *,
|
||||
int priority);
|
||||
int ofproto_dpif_add_lb_output_buckets(struct ofproto_dpif *, uint32_t bond_id,
|
||||
const ofp_port_t *slave_map);
|
||||
const ofp_port_t *member_map);
|
||||
int ofproto_dpif_delete_lb_output_buckets(struct ofproto_dpif *,
|
||||
uint32_t bond_id);
|
||||
bool ovs_lb_output_action_supported(struct ofproto_dpif *);
|
||||
|
@ -1225,7 +1225,7 @@ struct ofproto_class {
|
||||
* not support LACP.
|
||||
*/
|
||||
int (*port_get_lacp_stats)(const struct ofport *port,
|
||||
struct lacp_slave_stats *stats);
|
||||
struct lacp_member_stats *stats);
|
||||
|
||||
/* ## ----------------------- ## */
|
||||
/* ## OpenFlow Rule Functions ## */
|
||||
@ -1707,11 +1707,11 @@ struct ofproto_class {
|
||||
|
||||
/* If 's' is nonnull, this function registers a "bundle" associated with
|
||||
* client data pointer 'aux' in 'ofproto'. A bundle is the same concept as
|
||||
* a Port in OVSDB, that is, it consists of one or more "slave" devices
|
||||
* (Interfaces, in OVSDB) along with VLAN and LACP configuration and, if
|
||||
* there is more than one slave, a bonding configuration. If 'aux' is
|
||||
* already registered then this function updates its configuration to 's'.
|
||||
* Otherwise, this function registers a new bundle.
|
||||
* a Port in OVSDB, that is, it consists of one or more "member"
|
||||
* devices (Interfaces, in OVSDB) along with VLAN and LACP configuration
|
||||
* and, if there is more than one member, a bonding configuration. If 'aux'
|
||||
* is already registered then this function updates its configuration to
|
||||
* 's'. Otherwise, this function registers a new bundle.
|
||||
*
|
||||
* If 's' is NULL, this function unregisters the bundle registered on
|
||||
* 'ofproto' associated with client data pointer 'aux'. If no such bundle
|
||||
|
@ -1391,7 +1391,8 @@ ofproto_port_is_lacp_current(struct ofproto *ofproto, ofp_port_t ofp_port)
|
||||
}
|
||||
|
||||
int
|
||||
ofproto_port_get_lacp_stats(const struct ofport *port, struct lacp_slave_stats *stats)
|
||||
ofproto_port_get_lacp_stats(const struct ofport *port,
|
||||
struct lacp_member_stats *stats)
|
||||
{
|
||||
struct ofproto *ofproto = port->ofproto;
|
||||
int error;
|
||||
@ -1409,8 +1410,8 @@ ofproto_port_get_lacp_stats(const struct ofport *port, struct lacp_slave_stats *
|
||||
|
||||
/* Registers a "bundle" associated with client data pointer 'aux' in 'ofproto'.
|
||||
* A bundle is the same concept as a Port in OVSDB, that is, it consists of one
|
||||
* or more "slave" devices (Interfaces, in OVSDB) along with a VLAN
|
||||
* configuration plus, if there is more than one slave, a bonding
|
||||
* or more "member" devices (Interfaces, in OVSDB) along with a VLAN
|
||||
* configuration plus, if there is more than one member, a bonding
|
||||
* configuration.
|
||||
*
|
||||
* If 'aux' is already registered then this function updates its configuration
|
||||
|
@ -388,7 +388,8 @@ bool ofproto_port_bfd_status_changed(struct ofproto *, ofp_port_t ofp_port);
|
||||
int ofproto_port_get_bfd_status(struct ofproto *, ofp_port_t ofp_port,
|
||||
struct smap *);
|
||||
int ofproto_port_is_lacp_current(struct ofproto *, ofp_port_t ofp_port);
|
||||
int ofproto_port_get_lacp_stats(const struct ofport *, struct lacp_slave_stats *);
|
||||
int ofproto_port_get_lacp_stats(const struct ofport *,
|
||||
struct lacp_member_stats *);
|
||||
int ofproto_port_set_stp(struct ofproto *, ofp_port_t ofp_port,
|
||||
const struct ofproto_port_stp_settings *);
|
||||
int ofproto_port_get_stp_status(struct ofproto *, ofp_port_t ofp_port,
|
||||
@ -441,8 +442,8 @@ enum port_priority_tags_mode {
|
||||
struct ofproto_bundle_settings {
|
||||
char *name; /* For use in log messages. */
|
||||
|
||||
ofp_port_t *slaves; /* OpenFlow port numbers for slaves. */
|
||||
size_t n_slaves;
|
||||
ofp_port_t *members; /* OpenFlow port numbers for members. */
|
||||
size_t n_members;
|
||||
|
||||
enum port_vlan_mode vlan_mode; /* Selects mode for vlan and trunks */
|
||||
uint16_t qinq_ethtype;
|
||||
@ -452,10 +453,10 @@ struct ofproto_bundle_settings {
|
||||
enum port_priority_tags_mode use_priority_tags;
|
||||
/* Use 802.1p tag for frames in VLAN 0? */
|
||||
|
||||
struct bond_settings *bond; /* Must be nonnull iff if n_slaves > 1. */
|
||||
struct bond_settings *bond; /* Must be nonnull iff if n_members > 1. */
|
||||
|
||||
struct lacp_settings *lacp; /* Nonnull to enable LACP. */
|
||||
struct lacp_slave_settings *lacp_slaves; /* Array of n_slaves elements. */
|
||||
struct lacp_member_settings *lacp_members; /* Array of n_members elements. */
|
||||
|
||||
bool protected; /* Protected port mode */
|
||||
};
|
||||
|
@ -9,7 +9,7 @@ AT_BANNER([bundle link selection])
|
||||
|
||||
AT_SETUP([hrw bundle link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],members:1,2,3,4,5']],
|
||||
[0], [ignore])
|
||||
# 100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
|
||||
# 110000: disruption=0.50 (perfect=0.50) 0.50 0.50 0.00 0.00 0.00 0.00
|
||||
@ -80,7 +80,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([active_backup bundle link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,active_backup,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5,6']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,active_backup,ofport,NXM_NX_REG0[],members:1,2,3,4,5,6']],
|
||||
[0],
|
||||
[100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
|
||||
110000: disruption=0.00 (perfect=0.00) 1.00 0.00 0.00 0.00 0.00 0.00
|
||||
@ -152,7 +152,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([hrw bundle single link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],members:1']],
|
||||
[0], [ignore])
|
||||
# 1: disruption=1.00 (perfect=1.00) 1.00
|
||||
# 0: disruption=1.00 (perfect=1.00) 0.00
|
||||
@ -161,7 +161,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([hrw bundle no link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],members:']],
|
||||
[0], [ignore])
|
||||
AT_CLEANUP
|
||||
#: disruption=0.00 (perfect=0.00)
|
||||
@ -176,29 +176,29 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([bundle action bad fields])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([ovs-ofctl parse-flow 'actions=bundle(xyzzy,60,hrw,ofport,slaves:1,2))'], [1], [],
|
||||
[ovs-ofctl: xyzzy,60,hrw,ofport,slaves:1,2: unknown fields `xyzzy'
|
||||
AT_CHECK([ovs-ofctl parse-flow 'actions=bundle(xyzzy,60,hrw,ofport,members:1,2))'], [1], [],
|
||||
[ovs-ofctl: xyzzy,60,hrw,ofport,members:1,2: unknown fields `xyzzy'
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([bundle action bad algorithm])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([ovs-ofctl parse-flow 'actions=bundle(symmetric_l4,60,fubar,ofport,slaves:1,2))'], [1], [],
|
||||
[ovs-ofctl: symmetric_l4,60,fubar,ofport,slaves:1,2: unknown algorithm `fubar'
|
||||
AT_CHECK([ovs-ofctl parse-flow 'actions=bundle(symmetric_l4,60,fubar,ofport,members:1,2))'], [1], [],
|
||||
[ovs-ofctl: symmetric_l4,60,fubar,ofport,members:1,2: unknown algorithm `fubar'
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([bundle action bad slave type])
|
||||
AT_SETUP([bundle action bad member type])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([ovs-ofctl parse-flow 'actions=bundle(symmetric_l4,60,hrw,robot,slaves:1,2))'], [1], [],
|
||||
[ovs-ofctl: symmetric_l4,60,hrw,robot,slaves:1,2: unknown slave_type `robot'
|
||||
AT_CHECK([ovs-ofctl parse-flow 'actions=bundle(symmetric_l4,60,hrw,robot,members:1,2))'], [1], [],
|
||||
[ovs-ofctl: symmetric_l4,60,hrw,robot,members:1,2: unknown member_type `robot'
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([bundle action bad slave delimiter])
|
||||
AT_SETUP([bundle action bad member delimiter])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([ovs-ofctl parse-flow 'actions=bundle(symmetric_l4,60,hrw,ofport,robot:1,2))'], [1], [],
|
||||
[ovs-ofctl: symmetric_l4,60,hrw,ofport,robot:1,2: missing slave delimiter, expected `slaves' got `robot'
|
||||
[ovs-ofctl: symmetric_l4,60,hrw,ofport,robot:1,2: missing member delimiter, expected `members', got `robot'
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
@ -211,9 +211,9 @@ dnl Valgrind warnings for use-after-free bugs.
|
||||
AT_SETUP([bundle action with many ports])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
OVS_VSWITCHD_START
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=set_field:0x1->metadata,set_field:0x2->metadata,set_field:0x3->metadata,set_field:0x4->metadata,bundle(symmetric_l4,0,hrw,ofport,slaves:[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]])'])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=set_field:0x1->metadata,set_field:0x2->metadata,set_field:0x3->metadata,set_field:0x4->metadata,bundle(symmetric_l4,0,hrw,ofport,members:[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]])'])
|
||||
AT_CHECK([ovs-ofctl dump-flows br0 --no-stats], [0], [dnl
|
||||
actions=load:0x1->OXM_OF_METADATA[[]],load:0x2->OXM_OF_METADATA[[]],load:0x3->OXM_OF_METADATA[[]],load:0x4->OXM_OF_METADATA[[]],bundle(symmetric_l4,0,hrw,ofport,slaves:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)
|
||||
actions=load:0x1->OXM_OF_METADATA[[]],load:0x2->OXM_OF_METADATA[[]],load:0x3->OXM_OF_METADATA[[]],load:0x4->OXM_OF_METADATA[[]],bundle(symmetric_l4,0,hrw,ofport,members:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)
|
||||
])
|
||||
OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
@ -226,7 +226,7 @@ OVS_VSWITCHD_START([dnl
|
||||
add-port br0 p2 -- set Interface p2 type=dummy -- \
|
||||
set Interface p2 ofport_request=2
|
||||
])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=bundle(eth_src,50,active_backup,ofport,slaves:1,2)'])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=bundle(eth_src,50,active_backup,ofport,members:1,2)'])
|
||||
AT_CHECK([ovs-ofctl mod-port br0 p1 up])
|
||||
AT_CHECK([ovs-ofctl mod-port br0 p2 up])
|
||||
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=LOCAL,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06'], [0], [stdout])
|
||||
@ -264,7 +264,7 @@ OVS_VSWITCHD_START([dnl
|
||||
add-port br0 p2 -- set Interface p2 type=dummy -- \
|
||||
set Interface p2 ofport_request=2
|
||||
])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=bundle_load(eth_src,50,hrw,ofport,OXM_OF_ETH_SRC[[0..15]],slaves:1,2)'])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=bundle_load(eth_src,50,hrw,ofport,OXM_OF_ETH_SRC[[0..15]],members:1,2)'])
|
||||
AT_CHECK([ovs-ofctl mod-port br0 p1 down])
|
||||
AT_CHECK([ovs-ofctl mod-port br0 p2 down])
|
||||
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=LOCAL,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06'], [0], [stdout])
|
||||
@ -276,7 +276,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([hrw bundle symmetric_l3 link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],members:1,2,3,4,5']],
|
||||
[0], [ignore])
|
||||
# 100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
|
||||
# 110000: disruption=0.50 (perfect=0.50) 0.50 0.50 0.00 0.00 0.00 0.00
|
||||
@ -347,7 +347,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([active_backup bundle symmetric_l3 link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,active_backup,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5,6']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,active_backup,ofport,NXM_NX_REG0[],members:1,2,3,4,5,6']],
|
||||
[0],
|
||||
[100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
|
||||
110000: disruption=0.00 (perfect=0.00) 1.00 0.00 0.00 0.00 0.00 0.00
|
||||
@ -419,7 +419,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([hrw bundle symmetric_l3 single link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],slaves:1']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],members:1']],
|
||||
[0], [ignore])
|
||||
# 1: disruption=1.00 (perfect=1.00) 1.00
|
||||
# 0: disruption=1.00 (perfect=1.00) 0.00
|
||||
@ -428,7 +428,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([hrw bundle symmetric_l3 single link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],slaves:1']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],members:1']],
|
||||
[0], [ignore])
|
||||
# 1: disruption=1.00 (perfect=1.00) 1.00
|
||||
# 0: disruption=1.00 (perfect=1.00) 0.00
|
||||
@ -437,7 +437,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([hrw bundle symmetric_l3 no link selection])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],slaves:']],
|
||||
AT_CHECK([[ovstest test-bundle 'symmetric_l3,60,hrw,ofport,NXM_NX_REG0[],members:']],
|
||||
[0], [ignore])
|
||||
AT_CLEANUP
|
||||
#: disruption=0.00 (perfect=0.00)
|
||||
@ -446,9 +446,9 @@ AT_CLEANUP
|
||||
AT_SETUP([bundle symmetric_l3 action with many ports])
|
||||
AT_KEYWORDS([bundle_action])
|
||||
OVS_VSWITCHD_START
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=set_field:0x1->metadata,set_field:0x2->metadata,set_field:0x3->metadata,set_field:0x4->metadata,bundle(symmetric_l3,0,hrw,ofport,slaves:[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]])'])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 'actions=set_field:0x1->metadata,set_field:0x2->metadata,set_field:0x3->metadata,set_field:0x4->metadata,bundle(symmetric_l3,0,hrw,ofport,members:[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]])'])
|
||||
AT_CHECK([ovs-ofctl dump-flows br0 --no-stats], [0], [dnl
|
||||
actions=load:0x1->OXM_OF_METADATA[[]],load:0x2->OXM_OF_METADATA[[]],load:0x3->OXM_OF_METADATA[[]],load:0x4->OXM_OF_METADATA[[]],bundle(symmetric_l3,0,hrw,ofport,slaves:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)
|
||||
actions=load:0x1->OXM_OF_METADATA[[]],load:0x2->OXM_OF_METADATA[[]],load:0x3->OXM_OF_METADATA[[]],load:0x4->OXM_OF_METADATA[[]],bundle(symmetric_l3,0,hrw,ofport,members:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)
|
||||
])
|
||||
OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
146
tests/lacp.at
146
tests/lacp.at
@ -5,9 +5,9 @@ m4_define([STRIP_RECIRC_ID], [[sed '
|
||||
s/Recirc-ID.*$/<del>/
|
||||
' ]])
|
||||
|
||||
# Strips out active slave mac address since it may change over time.
|
||||
m4_define([STRIP_ACTIVE_SLAVE_MAC], [[sed '
|
||||
s/active slave mac.*$/<active slave mac del>/
|
||||
# Strips out active member mac address since it may change over time.
|
||||
m4_define([STRIP_ACTIVE_MEMBER_MAC], [[sed '
|
||||
s/active member mac.*$/<active member mac del>/
|
||||
' ]])
|
||||
|
||||
AT_SETUP([lacp - config])
|
||||
@ -27,7 +27,7 @@ AT_CHECK([ovs-appctl lacp/show], [0], [dnl
|
||||
aggregation key: 1
|
||||
lacp_time: slow
|
||||
|
||||
slave: p1: expired attached
|
||||
member: p1: expired attached
|
||||
port_id: 1
|
||||
port_priority: 65535
|
||||
may_enable: false
|
||||
@ -78,7 +78,7 @@ AT_CHECK([sed -e 's/aggregation key:.*/aggregation key: <omitted>/' < stdout], [
|
||||
aggregation key: <omitted>
|
||||
lacp_time: fast
|
||||
|
||||
slave: p1: expired attached
|
||||
member: p1: expired attached
|
||||
port_id: 11
|
||||
port_priority: 111
|
||||
may_enable: false
|
||||
@ -97,7 +97,7 @@ slave: p1: expired attached
|
||||
partner key: 0
|
||||
partner state: timeout
|
||||
|
||||
slave: p2: expired attached
|
||||
member: p2: expired attached
|
||||
port_id: 22
|
||||
port_priority: 222
|
||||
may_enable: false
|
||||
@ -127,12 +127,12 @@ downdelay: 0 ms
|
||||
lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
active slave mac: 00:00:00:00:00:00(none)
|
||||
active member mac: 00:00:00:00:00:00(none)
|
||||
|
||||
slave p1: disabled
|
||||
member p1: disabled
|
||||
may_enable: false
|
||||
|
||||
slave p2: disabled
|
||||
member p2: disabled
|
||||
may_enable: false
|
||||
|
||||
])
|
||||
@ -140,8 +140,8 @@ OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([lacp - negotiation])
|
||||
# Create bond0 on br0 with interfaces p0 and p1
|
||||
# and bond1 on br1 with interfaces p2 and p3
|
||||
# Create bond0 on br0 with members p0 and p1
|
||||
# and bond1 on br1 with members p2 and p3
|
||||
# with p0 patched to p2 and p1 patched to p3.
|
||||
OVS_VSWITCHD_START(
|
||||
[add-bond br0 bond0 p0 p1 bond_mode=balance-tcp lacp=active \
|
||||
@ -193,9 +193,9 @@ done
|
||||
AT_CHECK(
|
||||
[ovs-appctl lacp/show bond0
|
||||
ovs-appctl lacp/show bond1
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC ], [0], [stdout])
|
||||
AT_CHECK([sed '/active slave/d' stdout], [0], [dnl
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC ], [0], [stdout])
|
||||
AT_CHECK([sed '/active member/d' stdout], [0], [dnl
|
||||
---- bond0 ----
|
||||
status: active negotiated
|
||||
sys_id: aa:55:aa:55:00:00
|
||||
@ -203,7 +203,7 @@ AT_CHECK([sed '/active slave/d' stdout], [0], [dnl
|
||||
aggregation key: 2
|
||||
lacp_time: fast
|
||||
|
||||
slave: p0: current attached
|
||||
member: p0: current attached
|
||||
port_id: 1
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -222,7 +222,7 @@ slave: p0: current attached
|
||||
partner key: 4
|
||||
partner state: activity timeout aggregation synchronized collecting distributing
|
||||
|
||||
slave: p1: current attached
|
||||
member: p1: current attached
|
||||
port_id: 2
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -247,7 +247,7 @@ slave: p1: current attached
|
||||
aggregation key: 4
|
||||
lacp_time: fast
|
||||
|
||||
slave: p2: current attached
|
||||
member: p2: current attached
|
||||
port_id: 3
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -266,7 +266,7 @@ slave: p2: current attached
|
||||
partner key: 2
|
||||
partner state: activity timeout aggregation synchronized collecting distributing
|
||||
|
||||
slave: p3: current attached
|
||||
member: p3: current attached
|
||||
port_id: 4
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -295,10 +295,10 @@ lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
|
||||
slave p0: enabled
|
||||
member p0: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p1: enabled
|
||||
member p1: enabled
|
||||
may_enable: true
|
||||
|
||||
---- bond1 ----
|
||||
@ -312,16 +312,16 @@ lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
|
||||
slave p2: enabled
|
||||
member p2: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p3: enabled
|
||||
member p3: enabled
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
AT_CHECK([grep 'active slave$' stdout], [0], [dnl
|
||||
active slave
|
||||
active slave
|
||||
AT_CHECK([grep 'active member$' stdout], [0], [dnl
|
||||
active member
|
||||
active member
|
||||
])
|
||||
|
||||
# Redirect the patch link between p0 and p2 so that no packets get
|
||||
@ -335,8 +335,8 @@ ovs-appctl time/warp 4100 100
|
||||
AT_CHECK(
|
||||
[ovs-appctl lacp/show bond0
|
||||
ovs-appctl lacp/show bond1
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC ], [0], [dnl
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC ], [0], [dnl
|
||||
---- bond0 ----
|
||||
status: active negotiated
|
||||
sys_id: aa:55:aa:55:00:00
|
||||
@ -344,7 +344,7 @@ ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC ], [0], [d
|
||||
aggregation key: 2
|
||||
lacp_time: fast
|
||||
|
||||
slave: p0: expired attached
|
||||
member: p0: expired attached
|
||||
port_id: 1
|
||||
port_priority: 65535
|
||||
may_enable: false
|
||||
@ -363,7 +363,7 @@ slave: p0: expired attached
|
||||
partner key: 4
|
||||
partner state: activity timeout aggregation collecting distributing
|
||||
|
||||
slave: p1: current attached
|
||||
member: p1: current attached
|
||||
port_id: 2
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -388,7 +388,7 @@ slave: p1: current attached
|
||||
aggregation key: 4
|
||||
lacp_time: fast
|
||||
|
||||
slave: p2: expired attached
|
||||
member: p2: expired attached
|
||||
port_id: 3
|
||||
port_priority: 65535
|
||||
may_enable: false
|
||||
@ -407,7 +407,7 @@ slave: p2: expired attached
|
||||
partner key: 2
|
||||
partner state: activity timeout aggregation collecting distributing
|
||||
|
||||
slave: p3: current attached
|
||||
member: p3: current attached
|
||||
port_id: 4
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -435,13 +435,13 @@ downdelay: 0 ms
|
||||
lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p0: disabled
|
||||
member p0: disabled
|
||||
may_enable: false
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
---- bond1 ----
|
||||
@ -454,13 +454,13 @@ downdelay: 0 ms
|
||||
lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p2: disabled
|
||||
member p2: disabled
|
||||
may_enable: false
|
||||
|
||||
slave p3: enabled
|
||||
active slave
|
||||
member p3: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
@ -471,8 +471,8 @@ ovs-appctl time/warp 4100 100
|
||||
AT_CHECK(
|
||||
[ovs-appctl lacp/show bond0
|
||||
ovs-appctl lacp/show bond1
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC ], [0], [dnl
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC ], [0], [dnl
|
||||
---- bond0 ----
|
||||
status: active negotiated
|
||||
sys_id: aa:55:aa:55:00:00
|
||||
@ -480,7 +480,7 @@ ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC ], [0], [d
|
||||
aggregation key: 2
|
||||
lacp_time: fast
|
||||
|
||||
slave: p0: defaulted detached
|
||||
member: p0: defaulted detached
|
||||
port_id: 1
|
||||
port_priority: 65535
|
||||
may_enable: false
|
||||
@ -499,7 +499,7 @@ slave: p0: defaulted detached
|
||||
partner key: 0
|
||||
partner state:
|
||||
|
||||
slave: p1: current attached
|
||||
member: p1: current attached
|
||||
port_id: 2
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -524,7 +524,7 @@ slave: p1: current attached
|
||||
aggregation key: 4
|
||||
lacp_time: fast
|
||||
|
||||
slave: p2: defaulted detached
|
||||
member: p2: defaulted detached
|
||||
port_id: 3
|
||||
port_priority: 65535
|
||||
may_enable: false
|
||||
@ -543,7 +543,7 @@ slave: p2: defaulted detached
|
||||
partner key: 0
|
||||
partner state:
|
||||
|
||||
slave: p3: current attached
|
||||
member: p3: current attached
|
||||
port_id: 4
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -571,13 +571,13 @@ downdelay: 0 ms
|
||||
lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p0: disabled
|
||||
member p0: disabled
|
||||
may_enable: false
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
---- bond1 ----
|
||||
@ -590,13 +590,13 @@ downdelay: 0 ms
|
||||
lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p2: disabled
|
||||
member p2: disabled
|
||||
may_enable: false
|
||||
|
||||
slave p3: enabled
|
||||
active slave
|
||||
member p3: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
@ -612,8 +612,8 @@ ovs-appctl time/warp 30100 100
|
||||
AT_CHECK(
|
||||
[ovs-appctl lacp/show bond0
|
||||
ovs-appctl lacp/show bond1
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC ], [0], [dnl
|
||||
ovs-appctl bond/show bond0 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC
|
||||
ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC ], [0], [dnl
|
||||
---- bond0 ----
|
||||
status: active negotiated
|
||||
sys_id: aa:55:aa:55:00:00
|
||||
@ -621,7 +621,7 @@ ovs-appctl bond/show bond1 | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC ], [0], [d
|
||||
aggregation key: 2
|
||||
lacp_time: fast
|
||||
|
||||
slave: p0: current attached
|
||||
member: p0: current attached
|
||||
port_id: 1
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -640,7 +640,7 @@ slave: p0: current attached
|
||||
partner key: 4
|
||||
partner state: activity timeout aggregation synchronized collecting distributing
|
||||
|
||||
slave: p1: current attached
|
||||
member: p1: current attached
|
||||
port_id: 2
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -665,7 +665,7 @@ slave: p1: current attached
|
||||
aggregation key: 4
|
||||
lacp_time: fast
|
||||
|
||||
slave: p2: current attached
|
||||
member: p2: current attached
|
||||
port_id: 3
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -684,7 +684,7 @@ slave: p2: current attached
|
||||
partner key: 2
|
||||
partner state: activity timeout aggregation synchronized collecting distributing
|
||||
|
||||
slave: p3: current attached
|
||||
member: p3: current attached
|
||||
port_id: 4
|
||||
port_priority: 65535
|
||||
may_enable: true
|
||||
@ -712,13 +712,13 @@ downdelay: 0 ms
|
||||
lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p0: enabled
|
||||
member p0: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
---- bond1 ----
|
||||
@ -731,13 +731,13 @@ downdelay: 0 ms
|
||||
lacp_status: negotiated
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p2: enabled
|
||||
member p2: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p3: enabled
|
||||
active slave
|
||||
member p3: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
@ -771,8 +771,8 @@ ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
|
||||
# Set miss_send_len to 128, enabling port_status messages to our service connection.
|
||||
ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080
|
||||
|
||||
# Create bond0 on br0 with interfaces p0 and p1
|
||||
# and bond1 on br1 with interfaces p2 and p3
|
||||
# Create bond0 on br0 with members p0 and p1
|
||||
# and bond1 on br1 with members p2 and p3
|
||||
# with p0 patched to p2 and p1 patched to p3.
|
||||
AT_CHECK([ovs-vsctl add-bond br0 bond0 p0 p1 bond_mode=balance-tcp lacp=active \
|
||||
other-config:lacp-time=fast \
|
||||
@ -866,8 +866,8 @@ ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
|
||||
# Set miss_send_len to 128, enabling port_status messages to our service connection.
|
||||
ovs-appctl -t ovs-ofctl ofctl/send 0509000c0123456700000080
|
||||
|
||||
# Create bond0 on br0 with interfaces p0 and p1
|
||||
# and bond1 on br1 with interfaces p2 and p3
|
||||
# Create bond0 on br0 with members p0 and p1
|
||||
# and bond1 on br1 with members p2 and p3
|
||||
# with p0 patched to p2 and p1 patched to p3.
|
||||
AT_CHECK([ovs-vsctl add-bond br0 bond0 p0 p1 bond_mode=balance-tcp lacp=active \
|
||||
other-config:lacp-time=fast \
|
||||
@ -961,8 +961,8 @@ ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
|
||||
# Set miss_send_len to 128, enabling port_status messages to our service connection.
|
||||
ovs-appctl -t ovs-ofctl ofctl/send 0609000c0123456700000080
|
||||
|
||||
# Create bond0 on br0 with interfaces p0 and p1
|
||||
# and bond1 on br1 with interfaces p2 and p3
|
||||
# Create bond0 on br0 with members p0 and p1
|
||||
# and bond1 on br1 with members p2 and p3
|
||||
# with p0 patched to p2 and p1 patched to p3.
|
||||
AT_CHECK([ovs-vsctl add-bond br0 bond0 p0 p1 bond_mode=balance-tcp lacp=active \
|
||||
other-config:lacp-time=fast \
|
||||
|
@ -80,11 +80,11 @@ ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffff0000ffff0000
|
||||
# actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
|
||||
ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
|
||||
|
||||
# actions=bundle(eth_src,0,hrw,ofport,slaves:4,8)
|
||||
# actions=bundle(eth_src,0,hrw,ofport,members:4,8)
|
||||
ffff 0028 00002320 000c 0001 0000 0000 00000002 0002 0000 00000000 00000000 dnl
|
||||
0004 0008 00000000
|
||||
|
||||
# actions=bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[],slaves:4,8)
|
||||
# actions=bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[],members:4,8)
|
||||
ffff 0028 00002320 000d 0001 0000 0000 00000002 0002 001f 00010004 00000000 dnl
|
||||
0004 0008 00000000
|
||||
|
||||
@ -444,11 +444,11 @@ ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff
|
||||
# actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
|
||||
ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
|
||||
|
||||
# actions=bundle(eth_src,0,hrw,ofport,slaves:4,8)
|
||||
# actions=bundle(eth_src,0,hrw,ofport,members:4,8)
|
||||
ffff 0028 00002320 000c 0001 0000 0000 00000002 0002 0000 00000000 00000000 dnl
|
||||
0004 0008 00000000
|
||||
|
||||
# actions=bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[],slaves:4,8)
|
||||
# actions=bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[],members:4,8)
|
||||
ffff 0028 00002320 000d 0001 0000 0000 00000002 0002 001f 00010004 00000000 dnl
|
||||
0004 0008 00000000
|
||||
|
||||
@ -958,17 +958,17 @@ bad_action 'enqueue:asdf:123' 'asdf: enqueue to unknown port'
|
||||
# bundle
|
||||
bad_action 'bundle:123' '123: not enough arguments to bundle action'
|
||||
bad_action 'bundle(symmetric_l4,60,hrw,ofport,ports:1,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrw,ofport,ports:1,2,3,4,5: missing slave delimiter, expected \`slaves' got \`ports'"
|
||||
bad_action 'bundle(symmetric_l4,60,hrw,ofport,slaves:xyzzy,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrw,ofport,ports:1,2,3,4,5: missing member delimiter, expected \`members', got \`ports'"
|
||||
bad_action 'bundle(symmetric_l4,60,hrw,ofport,members:xyzzy,2,3,4,5)' \
|
||||
'xyzzy: bad port number'
|
||||
bad_action 'bundle(asymmetric_l4,60,hrw,ofport,slaves:1,2,3,4,5)' \
|
||||
"asymmetric_l4,60,hrw,ofport,slaves:1,2,3,4,5: unknown fields \`asymmetric_l4'"
|
||||
bad_action 'bundle(symmetric_l4,60,hrt,ofport,slaves:1,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrt,ofport,slaves:1,2,3,4,5: unknown algorithm \`hrt'"
|
||||
bad_action 'bundle(symmetric_l4,60,hrw,odpport,slaves:1,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrw,odpport,slaves:1,2,3,4,5: unknown slave_type \`odpport'"
|
||||
bad_action 'bundle_load(symmetric_l4,60,hrw,ofport,actset_output,slaves:1,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrw,ofport,actset_output,slaves:1,2,3,4,5: experimenter OXM field 'actset_output' not supported"
|
||||
bad_action 'bundle(asymmetric_l4,60,hrw,ofport,members:1,2,3,4,5)' \
|
||||
"asymmetric_l4,60,hrw,ofport,members:1,2,3,4,5: unknown fields \`asymmetric_l4'"
|
||||
bad_action 'bundle(symmetric_l4,60,hrt,ofport,members:1,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrt,ofport,members:1,2,3,4,5: unknown algorithm \`hrt'"
|
||||
bad_action 'bundle(symmetric_l4,60,hrw,odpport,members:1,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrw,odpport,members:1,2,3,4,5: unknown member_type \`odpport'"
|
||||
bad_action 'bundle_load(symmetric_l4,60,hrw,ofport,actset_output,members:1,2,3,4,5)' \
|
||||
"symmetric_l4,60,hrw,ofport,actset_output,members:1,2,3,4,5: experimenter OXM field 'actset_output' not supported"
|
||||
|
||||
# mod_vlan_vid
|
||||
bad_action 'mod_vlan_vid:6000' '6000: not a valid VLAN VID'
|
||||
|
@ -31,8 +31,8 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto-dpif - active-backup bonding (with primary)])
|
||||
|
||||
dnl Create br0 with interfaces p1, p2 and p7, creating bond0 with p1 and
|
||||
dnl p2 (p1 as primary) and br1 with interfaces p3, p4 and p8.
|
||||
dnl Create br0 with members p1, p2 and p7, creating bond0 with p1 and
|
||||
dnl p2 (p1 as primary) and br1 with members p3, p4 and p8.
|
||||
dnl toggle p1,p2 of bond0 up and down to test bonding in active-backup mode.
|
||||
dnl With p1 down and p2 up/active, bring p1 back up. Since p1 is the primary,
|
||||
dnl it should become active.
|
||||
@ -81,7 +81,7 @@ recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=ff:
|
||||
|
||||
ovs-appctl netdev-dummy/set-admin-state p1 up
|
||||
ovs-appctl time/warp 100
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC], [0], [dnl
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl
|
||||
---- bond0 ----
|
||||
bond_mode: active-backup
|
||||
bond may use recirculation: no, <del>
|
||||
@ -91,13 +91,13 @@ downdelay: 0 ms
|
||||
lacp_status: off
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: p1
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
slave p2: enabled
|
||||
member p2: enabled
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
@ -118,18 +118,18 @@ OVS_VSWITCHD_START(
|
||||
add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy --])
|
||||
AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])
|
||||
|
||||
dnl Make sure the initial primary interface is set
|
||||
dnl Make sure the initial primary member is set
|
||||
OVS_WAIT_UNTIL([test -n "`ovs-appctl bond/show | grep 'active-backup primary: p1'`"])
|
||||
|
||||
dnl Down the primary interface and verify that we switched. Then
|
||||
dnl Down the primary member and verify that we switched. Then
|
||||
dnl bring the primary back and verify that we switched back to the
|
||||
dnl primary.
|
||||
ovs-appctl netdev-dummy/set-admin-state p1 down
|
||||
ovs-appctl time/warp 100
|
||||
OVS_WAIT_UNTIL([test -n "`ovs-appctl bond/show | fgrep 'slave p1: disabled'`"])
|
||||
OVS_WAIT_UNTIL([test -n "`ovs-appctl bond/show | fgrep 'member p1: disabled'`"])
|
||||
ovs-appctl netdev-dummy/set-admin-state p1 up
|
||||
ovs-appctl time/warp 100
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC], [0], [dnl
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl
|
||||
---- bond0 ----
|
||||
bond_mode: active-backup
|
||||
bond may use recirculation: no, <del>
|
||||
@ -139,39 +139,39 @@ downdelay: 0 ms
|
||||
lacp_status: off
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: p1
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
slave p2: enabled
|
||||
member p2: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p3: enabled
|
||||
member p3: enabled
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
|
||||
dnl Now delete the primary and verify that the output shows that the
|
||||
dnl primary is no longer enslaved
|
||||
dnl primary is no longer an member
|
||||
ovs-vsctl --id=@p1 get Interface p1 -- remove Port bond0 interfaces @p1
|
||||
ovs-appctl time/warp 100
|
||||
OVS_WAIT_UNTIL([test -n "`ovs-appctl bond/show | fgrep 'active-backup primary: p1 (no such slave)'`"])
|
||||
OVS_WAIT_UNTIL([test -n "`ovs-appctl bond/show | fgrep 'active-backup primary: p1 (no such member)'`"])
|
||||
|
||||
dnl Now re-add the primary and verify that the output shows that the
|
||||
dnl primary is available again.
|
||||
dnl
|
||||
dnl First, get the UUIDs of the interfaces that exist on bond0.
|
||||
dnl First, get the UUIDs of the members that exist on bond0.
|
||||
dnl Strip the trailing ] so that we can add a new UUID to the end.
|
||||
uuids=`ovs-vsctl get Port bond0 interfaces | sed -e 's/]//'`
|
||||
dnl Create a new port "p1" and add its UUID to the set of interfaces
|
||||
dnl Create a new port "p1" and add its UUID to the set of members
|
||||
dnl on bond0.
|
||||
ovs-vsctl \
|
||||
--id=@p1 create Interface name=p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \
|
||||
set Port bond0 interfaces="$uuids, @p1]"
|
||||
ovs-appctl time/warp 100
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC], [0], [dnl
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl
|
||||
---- bond0 ----
|
||||
bond_mode: active-backup
|
||||
bond may use recirculation: no, <del>
|
||||
@ -181,16 +181,16 @@ downdelay: 0 ms
|
||||
lacp_status: off
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: p1
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
slave p2: enabled
|
||||
member p2: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p3: enabled
|
||||
member p3: enabled
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
@ -198,7 +198,7 @@ slave p3: enabled
|
||||
dnl Switch to another primary
|
||||
ovs-vsctl set port bond0 other_config:bond-primary=p2
|
||||
ovs-appctl time/warp 100
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC], [0], [dnl
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl
|
||||
---- bond0 ----
|
||||
bond_mode: active-backup
|
||||
bond may use recirculation: no, <del>
|
||||
@ -208,16 +208,16 @@ downdelay: 0 ms
|
||||
lacp_status: off
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: p2
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
slave p2: enabled
|
||||
member p2: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p3: enabled
|
||||
member p3: enabled
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
@ -225,7 +225,7 @@ slave p3: enabled
|
||||
dnl Remove the "bond-primary" config directive from the bond.
|
||||
AT_CHECK([ovs-vsctl remove Port bond0 other_config bond-primary])
|
||||
ovs-appctl time/warp 100
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_SLAVE_MAC], [0], [dnl
|
||||
OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl
|
||||
---- bond0 ----
|
||||
bond_mode: active-backup
|
||||
bond may use recirculation: no, <del>
|
||||
@ -235,16 +235,16 @@ downdelay: 0 ms
|
||||
lacp_status: off
|
||||
lacp_fallback_ab: false
|
||||
active-backup primary: <none>
|
||||
<active slave mac del>
|
||||
<active member mac del>
|
||||
|
||||
slave p1: enabled
|
||||
active slave
|
||||
member p1: enabled
|
||||
active member
|
||||
may_enable: true
|
||||
|
||||
slave p2: enabled
|
||||
member p2: enabled
|
||||
may_enable: true
|
||||
|
||||
slave p3: enabled
|
||||
member p3: enabled
|
||||
may_enable: true
|
||||
|
||||
])
|
||||
@ -253,8 +253,8 @@ OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto-dpif - active-backup bonding (without primary)])
|
||||
dnl Create br0 with interfaces p1, p2 and p7, creating bond0 with p1 and p2
|
||||
dnl and br1 with interfaces p3, p4 and p8.
|
||||
dnl Create br0 with members p1, p2 and p7, creating bond0 with p1 and p2
|
||||
dnl and br1 with members p3, p4 and p8.
|
||||
dnl toggle p1,p2 of bond0 up and down to test bonding in active-backup mode.
|
||||
OVS_VSWITCHD_START(
|
||||
[add-bond br0 bond0 p1 p2 bond_mode=active-backup --\
|
||||
@ -300,8 +300,8 @@ OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto-dpif - balance-slb bonding])
|
||||
# Create br0 with interfaces bond0(p1, p2, p3) and p7,
|
||||
# and br1 with interfaces p4, p5, p6 and p8.
|
||||
# Create br0 with members bond0(p1, p2, p3) and p7,
|
||||
# and br1 with members p4, p5, p6 and p8.
|
||||
# p1 <-> p4, p2 <-> p5, p3 <-> p6
|
||||
# Send some traffic, make sure the traffic are spread based on source mac.
|
||||
OVS_VSWITCHD_START(
|
||||
@ -343,8 +343,8 @@ OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto-dpif - balance-tcp bonding])
|
||||
# Create br0 with interfaces bond0(p1, p2, p3) and p7,
|
||||
# and br1 with interfaces bond1(p4, p5, p6) and p8.
|
||||
# Create br0 with members bond0(p1, p2, p3) and p7,
|
||||
# and br1 with members bond1(p4, p5, p6) and p8.
|
||||
# bond0 <-> bond1
|
||||
# Send some traffic, make sure the traffic are spread based on L4 headers.
|
||||
OVS_VSWITCHD_START(
|
||||
@ -2185,7 +2185,7 @@ cookie=0xd dl_src=60:66:66:66:00:02 actions=pop_mpls:0x0800,load:0xa000001->OXM_
|
||||
cookie=0xd dl_src=60:66:66:66:00:03 actions=pop_mpls:0x0800,move:OXM_OF_IPV4_DST[[]]->OXM_OF_IPV4_SRC[[]],controller
|
||||
cookie=0xd dl_src=60:66:66:66:00:04 actions=pop_mpls:0x0800,push:OXM_OF_IPV4_DST[[]],pop:OXM_OF_IPV4_SRC[[]],controller
|
||||
cookie=0xd dl_src=60:66:66:66:00:05 actions=pop_mpls:0x0800,multipath(eth_src,50,modulo_n,1,0,OXM_OF_IPV4_SRC[[0..7]]),controller
|
||||
cookie=0xd dl_src=60:66:66:66:00:06 actions=pop_mpls:0x0800,bundle_load(eth_src,50,hrw,ofport,OXM_OF_IPV4_SRC[[0..15]],slaves:1,2),controller
|
||||
cookie=0xd dl_src=60:66:66:66:00:06 actions=pop_mpls:0x0800,bundle_load(eth_src,50,hrw,ofport,OXM_OF_IPV4_SRC[[0..15]],members:1,2),controller
|
||||
cookie=0xd dl_src=60:66:66:66:00:07 actions=pop_mpls:0x0800,learn(table=1,hard_timeout=60,eth_type=0x800,nw_proto=6,OXM_OF_IPV4_SRC[[]]=OXM_OF_IPV4_DST[[]]),controller
|
||||
|
||||
cookie=0xd dl_src=60:66:66:66:00:08 actions=pop_mpls:0x0806,resubmit(1,1)
|
||||
@ -3183,7 +3183,7 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:03 actions=pop_mpls:0x0800,move:NXM_OF_IP_DST[[]]->NXM_OF_IP_SRC[[]],CONTROLLER:65535
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:04 actions=pop_mpls:0x0800,push:NXM_OF_IP_DST[[]],pop:NXM_OF_IP_SRC[[]],CONTROLLER:65535
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:05 actions=pop_mpls:0x0800,multipath(eth_src,50,modulo_n,1,0,NXM_OF_IP_SRC[[0..7]]),CONTROLLER:65535
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:06 actions=pop_mpls:0x0800,bundle_load(eth_src,50,hrw,ofport,NXM_OF_IP_SRC[[0..15]],slaves:1,2),CONTROLLER:65535
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:06 actions=pop_mpls:0x0800,bundle_load(eth_src,50,hrw,ofport,NXM_OF_IP_SRC[[0..15]],members:1,2),CONTROLLER:65535
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:07 actions=pop_mpls:0x0800,learn(table=1,hard_timeout=60,eth_type=0x800,nw_proto=6,NXM_OF_IP_SRC[[]]=NXM_OF_IP_DST[[]]),CONTROLLER:65535
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:09 actions=resubmit(,2),CONTROLLER:65535
|
||||
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:0a actions=pop_mpls:0x0800,mod_nw_dst:10.0.0.1,CONTROLLER:65535
|
||||
@ -8634,8 +8634,8 @@ OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto-dpif megaflow - normal, balance-tcp bonding])
|
||||
# Create bond0 on br0 with interfaces p0 and p1
|
||||
# and bond1 on br1 with interfaces p2 and p3
|
||||
# Create bond0 on br0 with members p0 and p1
|
||||
# and bond1 on br1 with members p2 and p3
|
||||
# with p0 patched to p2 and p1 patched to p3.
|
||||
OVS_VSWITCHD_START(
|
||||
[add-bond br0 bond0 p0 p1 bond_mode=balance-tcp lacp=active \
|
||||
@ -9023,7 +9023,7 @@ AT_CHECK([ovs-appctl bfd/show | sed -n '/^.*Session State:.*/p'], [0], [dnl
|
||||
Local Session State: up
|
||||
Remote Session State: up
|
||||
])
|
||||
# bond/show should show 'may-enable: true' for all slaves.
|
||||
# bond/show should show 'may-enable: true' for all members.
|
||||
AT_CHECK([ovs-appctl bond/show | sed -n '/^.*may_enable:.*/p'], [0], [dnl
|
||||
may_enable: true
|
||||
may_enable: true
|
||||
@ -11027,7 +11027,7 @@ AT_CHECK([ovs-vsctl add-port br0 p2 -- set int p2 type=dummy mtu_request=1600])
|
||||
AT_CHECK([ovs-vsctl wait-until Interface p2 mtu=1600])
|
||||
AT_CHECK([ovs-vsctl wait-until Interface br0 mtu=1600])
|
||||
|
||||
# Explicitly set mtu_request on the internal interface. This should prevent
|
||||
# Explicitly set mtu_request on the internal member. This should prevent
|
||||
# the MTU from being overriden.
|
||||
AT_CHECK([ovs-vsctl set int br0 mtu_request=1700])
|
||||
AT_CHECK([ovs-vsctl wait-until Interface br0 mtu=1700])
|
||||
|
@ -6322,12 +6322,12 @@ AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
|
||||
OFPT_ERROR: OFPBAC_BAD_SET_LEN
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata1[[0..31]], slaves:4,8)"], [1], [], [stderr])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata1[[0..31]], members:4,8)"], [1], [], [stderr])
|
||||
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
|
||||
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata0[[32..63]], slaves:4,8)"], [1], [], [stderr])
|
||||
AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata0[[32..63]], members:4,8)"], [1], [], [stderr])
|
||||
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
|
||||
OFPT_ERROR: OFPBAC_BAD_SET_LEN
|
||||
])
|
||||
|
@ -413,20 +413,20 @@ actions=multipath(eth_src, 50, hrw, 12, 0, NXM_NX_REG0[0..3]),multipath(symmetri
|
||||
table=1,actions=drop
|
||||
tun_id=0x1234000056780000/0xffff0000ffff0000,actions=drop
|
||||
metadata=0x1234ffff5678ffff/0xffff0000ffff0000,actions=drop
|
||||
actions=bundle(eth_src,50,active_backup,ofport,slaves:1)
|
||||
actions=bundle(symmetric_l4,60,hrw,ofport,slaves:2,3)
|
||||
actions=bundle(symmetric_l4,60,hrw,ofport,slaves:)
|
||||
actions=bundle(symmetric_l3,60,hrw,ofport,slaves:2,3)
|
||||
actions=bundle(symmetric_l3,60,hrw,ofport,slaves:)
|
||||
actions=output:1,bundle(eth_src,0,hrw,ofport,slaves:1),output:2
|
||||
actions=bundle_load(eth_src,50,active_backup,ofport,reg0,slaves:1)
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,reg0[0..15],slaves:[2,3])
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
|
||||
actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
actions=bundle_load(symmetric_l3,60,hrw,ofport,reg0[0..15],slaves:[2,3])
|
||||
actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
|
||||
actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
|
||||
actions=bundle(eth_src,50,active_backup,ofport,members:1)
|
||||
actions=bundle(symmetric_l4,60,hrw,ofport,members:2,3)
|
||||
actions=bundle(symmetric_l4,60,hrw,ofport,members:)
|
||||
actions=bundle(symmetric_l3,60,hrw,ofport,members:2,3)
|
||||
actions=bundle(symmetric_l3,60,hrw,ofport,members:)
|
||||
actions=output:1,bundle(eth_src,0,hrw,ofport,members:1),output:2
|
||||
actions=bundle_load(eth_src,50,active_backup,ofport,reg0,members:1)
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],members:2,3)
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,reg0[0..15],members:[2,3])
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],members:)
|
||||
actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..15],members:2,3)
|
||||
actions=bundle_load(symmetric_l3,60,hrw,ofport,reg0[0..15],members:[2,3])
|
||||
actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..30],members:)
|
||||
actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],members:1),output:2
|
||||
actions=resubmit:1,resubmit(2),resubmit(,3),resubmit(2,3)
|
||||
send_flow_rem,actions=output:1,output:NXM_NX_REG0,output:2,output:reg1[16..31],output:3
|
||||
check_overlap,actions=output:1,exit,output:2
|
||||
@ -469,20 +469,20 @@ NXT_FLOW_MOD: ADD table:255 actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0.
|
||||
NXT_FLOW_MOD: ADD table:1 actions=drop
|
||||
NXT_FLOW_MOD: ADD table:255 tun_id=0x1234000056780000/0xffff0000ffff0000 actions=drop
|
||||
NXT_FLOW_MOD: ADD table:255 metadata=0x1234000056780000/0xffff0000ffff0000 actions=drop
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(eth_src,50,active_backup,ofport,slaves:1)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l4,60,hrw,ofport,slaves:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l4,60,hrw,ofport,slaves:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l3,60,hrw,ofport,slaves:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l3,60,hrw,ofport,slaves:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle(eth_src,0,hrw,ofport,slaves:1),output:2
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(eth_src,50,active_backup,ofport,NXM_NX_REG0[],slaves:1)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(eth_src,50,active_backup,ofport,members:1)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l4,60,hrw,ofport,members:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l4,60,hrw,ofport,members:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l3,60,hrw,ofport,members:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l3,60,hrw,ofport,members:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle(eth_src,0,hrw,ofport,members:1),output:2
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(eth_src,50,active_backup,ofport,NXM_NX_REG0[],members:1)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],members:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],members:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],members:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..15],members:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..15],members:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l3,60,hrw,ofport,NXM_NX_REG0[0..30],members:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],members:1),output:2
|
||||
NXT_FLOW_MOD: ADD table:255 actions=resubmit:1,resubmit:2,resubmit(,3),resubmit(2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 send_flow_rem actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3
|
||||
NXT_FLOW_MOD: ADD table:255 check_overlap actions=output:1,exit,output:2
|
||||
|
@ -25,28 +25,28 @@
|
||||
#include "util.h"
|
||||
|
||||
#define N_FLOWS 50000
|
||||
#define MAX_SLAVES 8 /* Maximum supported by this test framework. */
|
||||
#define MAX_MEMBERS 8 /* Maximum supported by this test framework. */
|
||||
|
||||
struct slave {
|
||||
ofp_port_t slave_id;
|
||||
struct member {
|
||||
ofp_port_t member_id;
|
||||
|
||||
bool enabled;
|
||||
size_t flow_count;
|
||||
};
|
||||
|
||||
struct slave_group {
|
||||
size_t n_slaves;
|
||||
struct slave slaves[MAX_SLAVES];
|
||||
struct member_group {
|
||||
size_t n_members;
|
||||
struct member members[MAX_MEMBERS];
|
||||
};
|
||||
|
||||
static struct slave *
|
||||
slave_lookup(struct slave_group *sg, ofp_port_t slave_id)
|
||||
static struct member *
|
||||
member_lookup(struct member_group *sg, ofp_port_t member_id)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sg->n_slaves; i++) {
|
||||
if (sg->slaves[i].slave_id == slave_id) {
|
||||
return &sg->slaves[i];
|
||||
for (i = 0; i < sg->n_members; i++) {
|
||||
if (sg->members[i].member_id == member_id) {
|
||||
return &sg->members[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,12 +54,12 @@ slave_lookup(struct slave_group *sg, ofp_port_t slave_id)
|
||||
}
|
||||
|
||||
static bool
|
||||
slave_enabled_cb(ofp_port_t slave_id, void *aux)
|
||||
member_enabled_cb(ofp_port_t member_id, void *aux)
|
||||
{
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
|
||||
slave = slave_lookup(aux, slave_id);
|
||||
return slave ? slave->enabled : false;
|
||||
member = member_lookup(aux, member_id);
|
||||
return member ? member->enabled : false;
|
||||
}
|
||||
|
||||
static struct ofpact_bundle *
|
||||
@ -80,8 +80,8 @@ parse_bundle_actions(char *actions)
|
||||
bundle = ofpact_get_BUNDLE(xmemdup(action, action->len));
|
||||
ofpbuf_uninit(&ofpacts);
|
||||
|
||||
if (bundle->n_slaves > MAX_SLAVES) {
|
||||
ovs_fatal(0, "At most %u slaves are supported", MAX_SLAVES);
|
||||
if (bundle->n_members > MAX_MEMBERS) {
|
||||
ovs_fatal(0, "At most %u members are supported", MAX_MEMBERS);
|
||||
}
|
||||
|
||||
return bundle;
|
||||
@ -109,7 +109,7 @@ test_bundle_main(int argc, char *argv[])
|
||||
struct ofpact_bundle *bundle;
|
||||
struct flow *flows;
|
||||
size_t i, n_permute, old_n_enabled;
|
||||
struct slave_group sg;
|
||||
struct member_group sg;
|
||||
int old_active;
|
||||
|
||||
set_program_name(argv[0]);
|
||||
@ -120,17 +120,17 @@ test_bundle_main(int argc, char *argv[])
|
||||
|
||||
bundle = parse_bundle_actions(argv[1]);
|
||||
|
||||
/* Generate 'slaves' array. */
|
||||
sg.n_slaves = 0;
|
||||
for (i = 0; i < bundle->n_slaves; i++) {
|
||||
ofp_port_t slave_id = bundle->slaves[i];
|
||||
/* Generate 'members' array. */
|
||||
sg.n_members = 0;
|
||||
for (i = 0; i < bundle->n_members; i++) {
|
||||
ofp_port_t member_id = bundle->members[i];
|
||||
|
||||
if (slave_lookup(&sg, slave_id)) {
|
||||
ovs_fatal(0, "Redundant slaves are not supported. ");
|
||||
if (member_lookup(&sg, member_id)) {
|
||||
ovs_fatal(0, "Redundant members are not supported. ");
|
||||
}
|
||||
|
||||
sg.slaves[sg.n_slaves].slave_id = slave_id;
|
||||
sg.n_slaves++;
|
||||
sg.members[sg.n_members].member_id = member_id;
|
||||
sg.n_members++;
|
||||
}
|
||||
|
||||
/* Generate flows. */
|
||||
@ -141,14 +141,14 @@ test_bundle_main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Cycles through each possible liveness permutation for the given
|
||||
* n_slaves. The initial state is equivalent to all slaves down, so we
|
||||
* n_members. The initial state is equivalent to all members down, so we
|
||||
* skip it by starting at i = 1. We do one extra iteration to cover
|
||||
* transitioning from the final state back to the initial state. */
|
||||
old_n_enabled = 0;
|
||||
old_active = -1;
|
||||
n_permute = 1 << sg.n_slaves;
|
||||
n_permute = 1 << sg.n_members;
|
||||
for (i = 1; i <= n_permute + 1; i++) {
|
||||
struct slave *slave;
|
||||
struct member *member;
|
||||
size_t j, n_enabled, changed;
|
||||
double disruption, perfect;
|
||||
uint8_t mask;
|
||||
@ -156,27 +156,27 @@ test_bundle_main(int argc, char *argv[])
|
||||
|
||||
mask = i % n_permute;
|
||||
|
||||
/* Gray coding ensures that in each iteration exactly one slave
|
||||
/* Gray coding ensures that in each iteration exactly one member
|
||||
* changes its liveness. This makes the expected disruption a bit
|
||||
* easier to calculate, and is likely similar to how failures will be
|
||||
* experienced in the wild. */
|
||||
mask = mask ^ (mask >> 1);
|
||||
|
||||
/* Initialize slaves. */
|
||||
/* Initialize members. */
|
||||
n_enabled = 0;
|
||||
for (j = 0; j < sg.n_slaves; j++) {
|
||||
slave = &sg.slaves[j];
|
||||
slave->flow_count = 0;
|
||||
slave->enabled = ((1 << j) & mask) != 0;
|
||||
for (j = 0; j < sg.n_members; j++) {
|
||||
member = &sg.members[j];
|
||||
member->flow_count = 0;
|
||||
member->enabled = ((1 << j) & mask) != 0;
|
||||
|
||||
if (slave->enabled) {
|
||||
if (member->enabled) {
|
||||
n_enabled++;
|
||||
}
|
||||
}
|
||||
|
||||
active = -1;
|
||||
for (j = 0; j < sg.n_slaves; j++) {
|
||||
if (sg.slaves[j].enabled) {
|
||||
for (j = 0; j < sg.n_members; j++) {
|
||||
if (sg.members[j].enabled) {
|
||||
active = j;
|
||||
break;
|
||||
}
|
||||
@ -185,19 +185,19 @@ test_bundle_main(int argc, char *argv[])
|
||||
changed = 0;
|
||||
for (j = 0; j < N_FLOWS; j++) {
|
||||
struct flow *flow = &flows[j];
|
||||
ofp_port_t old_slave_id, ofp_port;
|
||||
ofp_port_t old_member_id, ofp_port;
|
||||
struct flow_wildcards wc;
|
||||
|
||||
old_slave_id = u16_to_ofp(flow->regs[0]);
|
||||
ofp_port = bundle_execute(bundle, flow, &wc, slave_enabled_cb,
|
||||
old_member_id = u16_to_ofp(flow->regs[0]);
|
||||
ofp_port = bundle_execute(bundle, flow, &wc, member_enabled_cb,
|
||||
&sg);
|
||||
flow->regs[0] = ofp_to_u16(ofp_port);
|
||||
|
||||
if (ofp_port != OFPP_NONE) {
|
||||
slave_lookup(&sg, ofp_port)->flow_count++;
|
||||
member_lookup(&sg, ofp_port)->flow_count++;
|
||||
}
|
||||
|
||||
if (old_slave_id != ofp_port) {
|
||||
if (old_member_id != ofp_port) {
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
@ -208,23 +208,23 @@ test_bundle_main(int argc, char *argv[])
|
||||
if (old_n_enabled || n_enabled) {
|
||||
perfect = 1.0 / MAX(old_n_enabled, n_enabled);
|
||||
} else {
|
||||
/* This will happen when 'sg.n_slaves' is 0. */
|
||||
/* This will happen when 'sg.n_members' is 0. */
|
||||
perfect = 0;
|
||||
}
|
||||
}
|
||||
|
||||
disruption = changed / (double)N_FLOWS;
|
||||
printf("%s: disruption=%.2f (perfect=%.2f)",
|
||||
mask_str(mask, sg.n_slaves), disruption, perfect);
|
||||
mask_str(mask, sg.n_members), disruption, perfect);
|
||||
|
||||
for (j = 0 ; j < sg.n_slaves; j++) {
|
||||
slave = &sg.slaves[j];
|
||||
for (j = 0 ; j < sg.n_members; j++) {
|
||||
member = &sg.members[j];
|
||||
double flow_percent;
|
||||
|
||||
flow_percent = slave->flow_count / (double)N_FLOWS;
|
||||
flow_percent = member->flow_count / (double)N_FLOWS;
|
||||
printf( " %.2f", flow_percent);
|
||||
|
||||
if (slave->enabled) {
|
||||
if (member->enabled) {
|
||||
double perfect_fp;
|
||||
|
||||
if (bundle->algorithm == NX_BD_ALG_ACTIVE_BACKUP) {
|
||||
@ -234,16 +234,16 @@ test_bundle_main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (fabs(flow_percent - perfect_fp) >= .01) {
|
||||
fprintf(stderr, "%s: slave %d: flow_percentage=%.5f for"
|
||||
fprintf(stderr, "%s: member %d: flow_percentage=%.5f for"
|
||||
" differs from perfect=%.5f by more than .01\n",
|
||||
mask_str(mask, sg.n_slaves), slave->slave_id,
|
||||
mask_str(mask, sg.n_members), member->member_id,
|
||||
flow_percent, perfect_fp);
|
||||
ok = false;
|
||||
}
|
||||
} else if (slave->flow_count) {
|
||||
fprintf(stderr, "%s: slave %d: disabled slave received"
|
||||
" flows.\n", mask_str(mask, sg.n_slaves),
|
||||
slave->slave_id);
|
||||
} else if (member->flow_count) {
|
||||
fprintf(stderr, "%s: member %d: disabled member received"
|
||||
" flows.\n", mask_str(mask, sg.n_members),
|
||||
member->member_id);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
@ -251,7 +251,7 @@ test_bundle_main(int argc, char *argv[])
|
||||
|
||||
if (fabs(disruption - perfect) >= .01) {
|
||||
fprintf(stderr, "%s: disruption=%.5f differs from perfect=%.5f by"
|
||||
" more than .01\n", mask_str(mask, sg.n_slaves),
|
||||
" more than .01\n", mask_str(mask, sg.n_members),
|
||||
disruption, perfect);
|
||||
ok = false;
|
||||
}
|
||||
|
@ -330,7 +330,8 @@ static void mirror_destroy(struct mirror *);
|
||||
static bool mirror_configure(struct mirror *);
|
||||
static void mirror_refresh_stats(struct mirror *);
|
||||
|
||||
static void iface_configure_lacp(struct iface *, struct lacp_slave_settings *);
|
||||
static void iface_configure_lacp(struct iface *,
|
||||
struct lacp_member_settings *);
|
||||
static bool iface_create(struct bridge *, const struct ovsrec_interface *,
|
||||
const struct ovsrec_port *);
|
||||
static bool iface_is_internal(const struct ovsrec_interface *iface,
|
||||
@ -1197,11 +1198,11 @@ port_configure(struct port *port)
|
||||
/* Get name. */
|
||||
s.name = port->name;
|
||||
|
||||
/* Get slaves. */
|
||||
s.n_slaves = 0;
|
||||
s.slaves = xmalloc(ovs_list_size(&port->ifaces) * sizeof *s.slaves);
|
||||
/* Get members. */
|
||||
s.n_members = 0;
|
||||
s.members = xmalloc(ovs_list_size(&port->ifaces) * sizeof *s.members);
|
||||
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
|
||||
s.slaves[s.n_slaves++] = iface->ofp_port;
|
||||
s.members[s.n_members++] = iface->ofp_port;
|
||||
}
|
||||
|
||||
/* Get VLAN tag. */
|
||||
@ -1270,16 +1271,16 @@ port_configure(struct port *port)
|
||||
if (s.lacp) {
|
||||
size_t i = 0;
|
||||
|
||||
s.lacp_slaves = xmalloc(s.n_slaves * sizeof *s.lacp_slaves);
|
||||
s.lacp_members = xmalloc(s.n_members * sizeof *s.lacp_members);
|
||||
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
|
||||
iface_configure_lacp(iface, &s.lacp_slaves[i++]);
|
||||
iface_configure_lacp(iface, &s.lacp_members[i++]);
|
||||
}
|
||||
} else {
|
||||
s.lacp_slaves = NULL;
|
||||
s.lacp_members = NULL;
|
||||
}
|
||||
|
||||
/* Get bond settings. */
|
||||
if (s.n_slaves > 1) {
|
||||
if (s.n_members > 1) {
|
||||
s.bond = &bond_settings;
|
||||
port_configure_bond(port, &bond_settings);
|
||||
} else {
|
||||
@ -1297,9 +1298,9 @@ port_configure(struct port *port)
|
||||
|
||||
/* Clean up. */
|
||||
free(s.cvlans);
|
||||
free(s.slaves);
|
||||
free(s.members);
|
||||
free(s.trunks);
|
||||
free(s.lacp_slaves);
|
||||
free(s.lacp_members);
|
||||
}
|
||||
|
||||
/* Pick local port hardware address and datapath ID for 'br'. */
|
||||
@ -2277,8 +2278,8 @@ find_local_hw_addr(const struct bridge *br, struct eth_addr *ea,
|
||||
} else {
|
||||
/* Choose the interface whose MAC address will represent the port.
|
||||
* The Linux kernel bonding code always chooses the MAC address of
|
||||
* the first slave added to a bond, and the Fedora networking
|
||||
* scripts always add slaves to a bond in alphabetical order, so
|
||||
* the first member added to a bond, and the Fedora networking
|
||||
* scripts always add members to a bond in alphabetical order, so
|
||||
* for compatibility we choose the interface with the name that is
|
||||
* first in alphabetical order. */
|
||||
LIST_FOR_EACH (candidate, port_elem, &port->ifaces) {
|
||||
@ -2961,7 +2962,7 @@ port_refresh_bond_status(struct port *port, bool force_update)
|
||||
return;
|
||||
}
|
||||
|
||||
if (bond_get_changed_active_slave(port->name, &mac, force_update)) {
|
||||
if (bond_get_changed_active_member(port->name, &mac, force_update)) {
|
||||
struct ds mac_s;
|
||||
|
||||
ds_init(&mac_s);
|
||||
@ -4505,7 +4506,7 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
|
||||
}
|
||||
|
||||
static void
|
||||
iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
|
||||
iface_configure_lacp(struct iface *iface, struct lacp_member_settings *s)
|
||||
{
|
||||
int priority, portid, key;
|
||||
|
||||
@ -4601,9 +4602,9 @@ port_configure_bond(struct port *port, struct bond_settings *s)
|
||||
|
||||
mac_s = port->cfg->bond_active_slave;
|
||||
if (!mac_s || !ovs_scan(mac_s, ETH_ADDR_SCAN_FMT,
|
||||
ETH_ADDR_SCAN_ARGS(s->active_slave_mac))) {
|
||||
ETH_ADDR_SCAN_ARGS(s->active_member_mac))) {
|
||||
/* OVSDB did not store the last active interface */
|
||||
s->active_slave_mac = eth_addr_zero;
|
||||
s->active_member_mac = eth_addr_zero;
|
||||
}
|
||||
|
||||
/* lb_output action is disabled by default. */
|
||||
|
@ -198,46 +198,46 @@ These commands manage bonded ports on an Open vSwitch's bridges. To
|
||||
understand some of these commands, it is important to understand a
|
||||
detail of the bonding implementation called ``source load balancing''
|
||||
(SLB). Instead of directly assigning Ethernet source addresses to
|
||||
slaves, the bonding implementation computes a function that maps an
|
||||
members, the bonding implementation computes a function that maps an
|
||||
48-bit Ethernet source addresses into an 8-bit value (a ``MAC hash''
|
||||
value). All of the Ethernet addresses that map to a single 8-bit
|
||||
value are then assigned to a single slave.
|
||||
value are then assigned to a single member.
|
||||
.IP "\fBbond/list\fR"
|
||||
Lists all of the bonds, and their slaves, on each bridge.
|
||||
Lists all of the bonds, and their members, on each bridge.
|
||||
.
|
||||
.IP "\fBbond/show\fR [\fIport\fR]"
|
||||
Lists all of the bond-specific information (updelay, downdelay, time
|
||||
until the next rebalance) about the given bonded \fIport\fR, or all
|
||||
bonded ports if no \fIport\fR is given. Also lists information about
|
||||
each slave: whether it is enabled or disabled, the time to completion
|
||||
each members: whether it is enabled or disabled, the time to completion
|
||||
of an updelay or downdelay if one is in progress, whether it is the
|
||||
active slave, the hashes assigned to the slave. Any LACP information
|
||||
active member, the hashes assigned to the member. Any LACP information
|
||||
related to this bond may be found using the \fBlacp/show\fR command.
|
||||
.
|
||||
.IP "\fBbond/migrate\fR \fIport\fR \fIhash\fR \fIslave\fR"
|
||||
Only valid for SLB bonds. Assigns a given MAC hash to a new slave.
|
||||
.IP "\fBbond/migrate\fR \fIport\fR \fIhash\fR \fImember\fR"
|
||||
Only valid for SLB bonds. Assigns a given MAC hash to a new member.
|
||||
\fIport\fR specifies the bond port, \fIhash\fR the MAC hash to be
|
||||
migrated (as a decimal number between 0 and 255), and \fIslave\fR the
|
||||
new slave to be assigned.
|
||||
migrated (as a decimal number between 0 and 255), and \fImember\fR the
|
||||
new member to be assigned.
|
||||
.IP
|
||||
The reassignment is not permanent: rebalancing or fail-over will
|
||||
cause the MAC hash to be shifted to a new slave in the usual
|
||||
cause the MAC hash to be shifted to a new member in the usual
|
||||
manner.
|
||||
.IP
|
||||
A MAC hash cannot be migrated to a disabled slave.
|
||||
.IP "\fBbond/set\-active\-slave\fR \fIport\fR \fIslave\fR"
|
||||
Sets \fIslave\fR as the active slave on \fIport\fR. \fIslave\fR must
|
||||
A MAC hash cannot be migrated to a disabled member.
|
||||
.IP "\fBbond/set\-active\-member\fR \fIport\fR \fImember\fR"
|
||||
Sets \fImember\fR as the active member on \fIport\fR. \fImember\fR must
|
||||
currently be enabled.
|
||||
.IP
|
||||
The setting is not permanent: a new active slave will be selected
|
||||
if \fIslave\fR becomes disabled.
|
||||
.IP "\fBbond/enable\-slave\fR \fIport\fR \fIslave\fR"
|
||||
.IQ "\fBbond/disable\-slave\fR \fIport\fR \fIslave\fR"
|
||||
Enables (or disables) \fIslave\fR on the given bond \fIport\fR, skipping any
|
||||
The setting is not permanent: a new active member will be selected
|
||||
if \fImember\fR becomes disabled.
|
||||
.IP "\fBbond/enable\-member\fR \fIport\fR \fImember\fR"
|
||||
.IQ "\fBbond/disable\-member\fR \fIport\fR \fImember\fR"
|
||||
Enables (or disables) \fImember\fR on the given bond \fIport\fR, skipping any
|
||||
updelay (or downdelay).
|
||||
.IP
|
||||
This setting is not permanent: it persists only until the carrier
|
||||
status of \fIslave\fR changes.
|
||||
status of \fImember\fR changes.
|
||||
.IP "\fBbond/hash\fR \fImac\fR [\fIvlan\fR] [\fIbasis\fR]"
|
||||
Returns the hash value which would be used for \fImac\fR with \fIvlan\fR
|
||||
and \fIbasis\fR if specified.
|
||||
@ -245,7 +245,7 @@ and \fIbasis\fR if specified.
|
||||
.IP "\fBlacp/show\fR [\fIport\fR]"
|
||||
Lists all of the LACP related information about the given \fIport\fR:
|
||||
active or passive, aggregation key, system id, and system priority. Also
|
||||
lists information about each slave: whether it is enabled or disabled,
|
||||
lists information about each member: whether it is enabled or disabled,
|
||||
whether it is attached or detached, port id and priority, actor
|
||||
information, and partner information. If \fIport\fR is not specified,
|
||||
then displays detailed information about all interfaces with CFM
|
||||
@ -253,7 +253,7 @@ enabled.
|
||||
.
|
||||
.IP "\fBlacp/stats-show\fR [\fIport\fR]"
|
||||
Lists various stats about LACP PDUs (number of RX/TX PDUs, bad PDUs received)
|
||||
and slave state (number of time slave's state expired/defaulted and carrier
|
||||
and member state (number of times its state expired/defaulted and carrier
|
||||
status changed) for the given \fIport\fR. If \fIport\fR is not specified,
|
||||
then displays stats of all interfaces with LACP enabled.
|
||||
.SS "DPCTL DATAPATH DEBUGGING COMMANDS"
|
||||
|
@ -1949,15 +1949,16 @@
|
||||
<dl>
|
||||
<dt><code>balance-slb</code></dt>
|
||||
<dd>
|
||||
Balances flows among slaves based on source MAC address and output
|
||||
VLAN, with periodic rebalancing as traffic patterns change.
|
||||
Balances flows among members based on source MAC address and
|
||||
output VLAN, with periodic rebalancing as traffic patterns change.
|
||||
</dd>
|
||||
|
||||
<dt><code>active-backup</code></dt>
|
||||
<dd>
|
||||
Assigns all flows to one slave, failing over to a backup slave when
|
||||
the active slave is disabled. This is the only bonding mode in which
|
||||
interfaces may be plugged into different upstream switches.
|
||||
Assigns all flows to one member, failing over to a backup
|
||||
member when the active member is disabled. This is the
|
||||
only bonding mode in which interfaces may be plugged into different
|
||||
upstream switches.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@ -1971,8 +1972,8 @@
|
||||
<dl>
|
||||
<dt><code>balance-tcp</code></dt>
|
||||
<dd>
|
||||
Balances flows among slaves based on L3 and L4 protocol information
|
||||
such as IP addresses and TCP/UDP ports.
|
||||
Balances flows among members based on L3 and L4 protocol
|
||||
information such as IP addresses and TCP/UDP ports.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@ -1987,20 +1988,20 @@
|
||||
|
||||
<column name="other_config" key="bond-hash-basis"
|
||||
type='{"type": "integer"}'>
|
||||
An integer hashed along with flows when choosing output slaves in load
|
||||
balanced bonds. When changed, all flows will be assigned different
|
||||
hash values possibly causing slave selection decisions to change. Does
|
||||
not affect bonding modes which do not employ load balancing such as
|
||||
<code>active-backup</code>.
|
||||
An integer hashed along with flows when choosing output members
|
||||
in load balanced bonds. When changed, all flows will be assigned
|
||||
different hash values possibly causing member selection
|
||||
decisions to change. Does not affect bonding modes which do not employ
|
||||
load balancing such as <code>active-backup</code>.
|
||||
</column>
|
||||
|
||||
<column name="other_config" key="lb-output-action"
|
||||
type='{"type": "boolean"}'>
|
||||
Enable/disable usage of optimized <code>lb_output</code> action for
|
||||
balancing flows among output slaves in load balanced bonds in
|
||||
balancing flows among output members in load balanced bonds in
|
||||
<code>balance-tcp</code>. When enabled, it uses optimized path for
|
||||
balance-tcp mode by using rss hash and avoids recirculation.
|
||||
This knob does not affect other balancing modes.
|
||||
balance-tcp mode by using rss hash and avoids recirculation. This knob
|
||||
does not affect other balancing modes.
|
||||
</column>
|
||||
|
||||
<column name="other_config" key="bond-primary"
|
||||
@ -2390,7 +2391,8 @@
|
||||
</group>
|
||||
|
||||
<column name="bond_active_slave">
|
||||
For a bonded port, record the mac address of the current active slave.
|
||||
For a bonded port, record the MAC address of the current active
|
||||
member.
|
||||
</column>
|
||||
|
||||
<group title="Port Statistics">
|
||||
@ -2480,7 +2482,8 @@
|
||||
<li>For the local interface, the default is the lowest-numbered MAC
|
||||
address among the other bridge ports, either the value of the
|
||||
<ref table="Port" column="mac"/> in its <ref table="Port"/> record,
|
||||
if set, or its actual MAC (for bonded ports, the MAC of its slave
|
||||
if set, or its actual MAC (for bonded ports, the MAC of its
|
||||
member
|
||||
whose name is first in alphabetical order). Internal ports and
|
||||
bridge ports that are used as port mirroring destinations (see the
|
||||
<ref table="Mirror"/> table) are ignored.</li>
|
||||
|
Loading…
x
Reference in New Issue
Block a user