Hi, Aaron
On Fri, Oct 10, 2025 at 11:48 PM Aaron Conole <[email protected]> wrote:
>
> Hi Changliang,
>
> Changliang Wu <[email protected]> writes:
>
> > On most switches, if STP is enabled and the port connected to OVS
> > is not in edge mode, when OVS service restart and negotiate LACP,
> > which will trigger STP recalculation.
> >
> > During this time, traffic on the LACP interface will be blocked
> > for several seconds(up to 5s+).
> >
> > Test in Mellanox Switch
> > OvS LACP: Fast Mode
> > Switch LACP | STP Mode | Downtime
> > ------------|-------------|---------
> > Fast/Slow | on - normal | 3.1s
> > Fast/Slow | off / edge | 0.2s
> >
> > This patch propose a solution, similar to flow restore,
> > 1. save LACP negotiation status
> > 2. pause LACP process
> > 3. restart OvS service
> > 4. inject LACP status into vswitchd
> > 5. resume LACP process
> >
> > Test Results with this patch
> > Switch LACP | STP Mode | Downtime
> > ------------|-------------|---------
> > Fast | on - normal | 0.3s
> > Slow | on - normal | 0.0s
> > Fast/Slow | off / edge | 0.0s
> >
> > Signed-off-by: Changliang Wu <[email protected]>
> > ---
>
> This is quite a hack, but I don't know that it is appropriate. For
> example, we don't know how long the vswitchd service will be down.
> Unlike flows, which are a user configuration, LACP negotiation is a
> process between two peers. Restoring state doesn't make much sense to
> me.
Yes, this is just an experimental draft.
The LACP bond interface disconnects for 3+ seconds when reload,
optimizing this downtime may be worthwhile.
'Restoring state' is one possible solution, and modifying the LACP
state machine,
as mentioned below, is also a possible solution.
>
> > lib/lacp.c | 272 +++++++++++++++++++++++++++++++++++++++++
> > ofproto/ofproto-dpif.c | 5 +-
> > ofproto/ofproto.c | 14 +++
> > ofproto/ofproto.h | 2 +
> > utilities/ovs-lib.in | 46 ++++++-
> > utilities/ovs-save | 159 ++++++++++++++++++++++++
> > vswitchd/bridge.c | 5 +
> > 7 files changed, 499 insertions(+), 4 deletions(-)
>
> In the future, if you introduce commands and user visible behavior,
> please add NEWS entry. This kind of behavior would be visible to the
> user, and these commands are likewise visible.
Noted with thanks.
>
> > diff --git a/lib/lacp.c b/lib/lacp.c
> > index 3252f17eb..251f63dbe 100644
> > --- a/lib/lacp.c
> > +++ b/lib/lacp.c
> > @@ -25,6 +25,7 @@
> > #include "dp-packet.h"
> > #include "ovs-atomic.h"
> > #include "packets.h"
> > +#include "openvswitch/ofp-parse.h"
> > #include "openvswitch/poll-loop.h"
> > #include "seq.h"
> > #include "openvswitch/shash.h"
> > @@ -168,6 +169,7 @@ 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;
> > +static unixctl_cb_func lacp_unixctl_set;
> >
> > /* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */
> > static void
> > @@ -229,6 +231,8 @@ lacp_init(void)
> > lacp_unixctl_show, NULL);
> > unixctl_command_register("lacp/show-stats", "[port]", 0, 1,
> > lacp_unixctl_show_stats, NULL);
> > + unixctl_command_register("lacp/set", "[port]", 3, INT_MAX,
> > + lacp_unixctl_set, NULL);
>
> Indentation here is not correct.
>
> > }
>
> FYI, I didn't review the code beyond this point. I think the approach
> here isn't acceptable. Perhaps we could look at how the LACP
> initialization phase may be improved.
>
> >
> > static void
> > @@ -940,6 +944,34 @@ lacp_find(const char *name) OVS_REQUIRES(mutex)
> > return NULL;
> > }
> >
> > +static struct member *
> > +lacp_member_find(struct lacp *lacp, const char *name) OVS_REQUIRES(mutex)
> > +{
> > + struct member *member;
> > +
> > + HMAP_FOR_EACH_SAFE (member, node, &lacp->members) {
> > + if (!strcmp(member->name, name)) {
> > + return member;
> > + }
> > + }
> > +
> > + return NULL;
> > +}
> > +
> > +static struct member *
> > +lacp_member_find_by_key(struct lacp *lacp, uint16_t key)
> > OVS_REQUIRES(mutex)
> > +{
> > + struct member *member;
> > +
> > + HMAP_FOR_EACH_SAFE (member, node, &lacp->members) {
> > + if (member->port_id == key) {
> > + return member;
> > + }
> > + }
> > +
> > + return NULL;
> > +}
> > +
> > static void
> > ds_put_lacp_state(struct ds *ds, uint8_t state)
> > {
> > @@ -1219,5 +1251,245 @@ lacp_get_member_stats(const struct lacp *lacp,
> > const void *member_,
> > }
> > ovs_mutex_unlock(&mutex);
> > return ret;
> > +}
> > +
> > +static void
> > +lacp_port_set(struct unixctl_conn *conn, struct lacp *lacp, const char
> > *parms)
> > + OVS_REQUIRES(mutex)
> > +{
> > + char *value;
> > + char *key;
> > + char **p = (char **)&parms;
> > + while (ofputil_parse_key_value(p, &key, &value)) {
> > + lacp->update = false;
> > + uint32_t tmp;
> > + if (nullable_string_is_equal(key, "status")) {
> > + if (strstr(value, "active")) {
> > + lacp->active = true;
> > + }
> > + if (strstr(value, "negotiated")) {
> > + lacp->negotiated = true;
> > + }
> > +
> > + } else if (nullable_string_is_equal(key, "sys_id")) {
> > + if (!eth_addr_from_string(value, &lacp->sys_id)) {
> > + unixctl_command_reply_error(conn, "invalid port sys_id");
> > + return;
> > + }
> > + } else if (nullable_string_is_equal(key, "sys_priority")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid port
> > sys_prority");
> > + return;
> > + }
> > + lacp->sys_priority = tmp;
> > + } else if (nullable_string_is_equal(key, "key")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid port key");
> > + return;
> > + }
> > + lacp->key_member = lacp_member_find_by_key(lacp, tmp);
> > + }
> > + }
> > +}
> > +
> > +static uint8_t
> > +lacp_state_from_str(const char *s)
> > +{
> > + uint8_t state = 0;
> > + if (strstr(s, "activity")) {
> > + state |= LACP_STATE_ACT;
> > + }
> > + if (strstr(s, "timeout")) {
> > + state |= LACP_STATE_TIME;
> > + }
> > + if (strstr(s, "aggregation")) {
> > + state |= LACP_STATE_AGG;
> > + }
> > + if (strstr(s, "synchronized")) {
> > + state |= LACP_STATE_SYNC;
> > + }
> > + if (strstr(s, "collecting")) {
> > + state |= LACP_STATE_COL;
> > + }
> > + if (strstr(s, "distributing")) {
> > + state |= LACP_STATE_DIST;
> > + }
> > + if (strstr(s, "defaulted")) {
> > + state |= LACP_STATE_DEF;
> > + }
> > + if (strstr(s, "expired")) {
> > + state |= LACP_STATE_EXP;
> > + }
> > + return state;
> > +}
> >
> > +static void
> > +lacp_member_set(struct unixctl_conn *conn, struct member *member,
> > + const char *op, const char *parms) OVS_REQUIRES(mutex)
> > +{
> > + char *value;
> > + char *key;
> > + char **p = (char **)&parms;
> > + if (nullable_string_is_equal(op, "member")) {
> > + while (ofputil_parse_key_value(p, &key, &value)) {
> > + uint32_t tmp;
> > + if (nullable_string_is_equal(key, "port_id")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "port_id");
> > + return;
> > + }
> > + member->port_id = tmp;
> > + } else if (nullable_string_is_equal(key, "port_priority")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "port_priority");
> > + return;
> > + }
> > + member->port_priority = tmp;
> > + } else if (nullable_string_is_equal(key, "status")) {
> > + if (strstr(value, "current")) {
> > + member->status = LACP_CURRENT;
> > + member->carrier_up = true;
> > + } else if (strstr(value, "expired")) {
> > + member->status = LACP_EXPIRED;
> > + } else if (strstr(value, "defaulted")) {
> > + member->status = LACP_DEFAULTED;
> > + }
> > +
> > + if (strstr(value, "attached")) {
> > + member->attached = true;
> > + }
> > + }
> > + }
> > + } else if (nullable_string_is_equal(op, "actor")) {
> > + while (ofputil_parse_key_value(p, &key, &value)) {
> > + uint32_t tmp;
> > + if (nullable_string_is_equal(key, "sys_id")) {
> > + struct eth_addr addr;
> > + if (!eth_addr_from_string(value, &addr)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "actor sys_id");
> > + return;
> > + }
> > + member->ntt_actor.sys_id = addr;
> > + } else if (nullable_string_is_equal(key, "sys_priority")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "actor
> > sys_priority");
> > + return;
> > + }
> > + member->ntt_actor.sys_priority = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "port_id")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "actor port_id");
> > + return;
> > + }
> > + member->ntt_actor.port_id = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "port_priority")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "actor
> > port_priority");
> > + return;
> > + }
> > + member->ntt_actor.port_priority = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "key")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "actor key");
> > + return;
> > + }
> > + member->ntt_actor.key = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "state")) {
> > + member->ntt_actor.state = lacp_state_from_str(value);
> > + VLOG_INFO("member->ntt_actor.state (%p) (%d)",
> > + &(member->ntt_actor.state),
> > member->ntt_actor.state);
> > + }
> > + }
> > + } else if (nullable_string_is_equal(op, "partner")) {
> > + while (ofputil_parse_key_value(p, &key, &value)) {
> > + uint32_t tmp;
> > + if (nullable_string_is_equal(key, "sys_id")) {
> > + struct eth_addr addr;
> > + if (!eth_addr_from_string(value, &addr)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "partner sys_id");
> > + return;
> > + }
> > + member->partner.sys_id = addr;
> > + } else if (nullable_string_is_equal(key, "sys_priority")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "partner
> > sys_priority");
> > + return;
> > + }
> > + member->partner.sys_priority = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "port_id")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "partner port_id");
> > + return;
> > + }
> > + member->partner.port_id = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "port_priority")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "partner
> > port_priority");
> > + return;
> > + }
> > + member->partner.port_priority = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "key")) {
> > + if (!str_to_uint(value, 10, &tmp)) {
> > + unixctl_command_reply_error(conn, "invalid member "
> > + "partner key");
> > + return;
> > + }
> > + member->partner.key = htons(tmp);
> > + } else if (nullable_string_is_equal(key, "state")) {
> > + member->partner.state = lacp_state_from_str(value);
> > + }
> > + }
> > + } else {
> > + unixctl_command_reply_error(conn, "invalid member op");
> > + }
> > + timer_set_duration(&member->tx, LACP_FAST_TIME_TX);
> > + timer_set_duration(&member->rx, LACP_FAST_TIME_TX);
> > +}
> > +
> > +static void
> > +lacp_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
> > + void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
> > +{
> > + struct member *member;
> > + struct lacp *lacp;
> > +
> > + lacp_lock();
> > + lacp = lacp_find(argv[1]);
> > + if (!lacp) {
> > + unixctl_command_reply_error(conn, "lacp port not found");
> > + goto out;
> > + }
> > +
> > + if (nullable_string_is_equal(argv[2], "port")) {
> > + lacp_port_set(conn, lacp, argv[3]);
> > + } else if (nullable_string_is_equal(argv[2], "member")) {
> > + member = lacp_member_find(lacp, argv[3]);
> > + if (!member) {
> > + unixctl_command_reply_error(conn, "lacp member not found");
> > + goto out;
> > + }
> > + if (argc < 5) {
> > + unixctl_command_reply_error(conn, "invalid member parms");
> > + goto out;
> > + }
> > + lacp_member_set(conn, member, argv[4], argv[5]);
> > + } else {
> > + unixctl_command_reply_error(conn, "invalid op type");
> > + goto out;
> > + }
> > +
> > +out:
> > + unixctl_command_reply(conn, NULL);
> > + lacp_unlock();
> > }
> > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> > index ed9e44ce2..28657f0e8 100644
> > --- a/ofproto/ofproto-dpif.c
> > +++ b/ofproto/ofproto-dpif.c
> > @@ -41,6 +41,7 @@
> > #include "nx-match.h"
> > #include "odp-util.h"
> > #include "odp-execute.h"
> > +#include "ofproto/ofproto.h"
> > #include "ofproto/ofproto-dpif.h"
> > #include "ofproto/ofproto-provider.h"
> > #include "ofproto-dpif-ipfix.h"
> > @@ -3702,7 +3703,6 @@ send_pdu_cb(void *port_, const void *pdu, size_t
> > pdu_size)
> > struct ofport_dpif *port = port_;
> > struct eth_addr ea;
> > int error;
> > -
> > error = netdev_get_etheraddr(port->up.netdev, &ea);
> > if (!error) {
> > struct dp_packet packet;
> > @@ -3781,6 +3781,9 @@ bundle_send_learning_packets(struct ofbundle *bundle)
> > static void
> > bundle_run(struct ofbundle *bundle)
> > {
> > + if (bundle->lacp && ofproto_get_lacp_restore_wait()) {
> > + return;
> > + }
> > if (bundle->lacp) {
> > lacp_run(bundle->lacp, send_pdu_cb);
> > }
> > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> > index 6fa18228b..6f587c21f 100644
> > --- a/ofproto/ofproto.c
> > +++ b/ofproto/ofproto.c
> > @@ -326,6 +326,8 @@ static struct vlog_rate_limit rl =
> > VLOG_RATE_LIMIT_INIT(1, 5);
> >
> > /* The default value of true waits for flow restore. */
> > static bool flow_restore_wait = true;
> > +/* The default value of true waits for lacp restore. */
> > +static bool lacp_restore_wait = true;
> >
> > /* Must be called to initialize the ofproto library.
> > *
> > @@ -997,6 +999,18 @@ ofproto_get_flow_restore_wait(void)
> > return flow_restore_wait;
> > }
> >
> > +void
> > +ofproto_set_lacp_restore_wait(bool lacp_restore_wait_db)
> > +{
> > + lacp_restore_wait = lacp_restore_wait_db;
> > +}
> > +
> > +bool
> > +ofproto_get_lacp_restore_wait(void)
> > +{
> > + return lacp_restore_wait;
> > +}
> > +
> > /* Retrieve datapath capabilities. */
> > void
> > ofproto_get_datapath_cap(const char *datapath_type, struct smap *dp_cap)
> > diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
> > index 3f85509a1..e8e69b0da 100644
> > --- a/ofproto/ofproto.h
> > +++ b/ofproto/ofproto.h
> > @@ -382,6 +382,8 @@ int ofproto_set_local_sample(struct ofproto *ofproto,
> > size_t n_options);
> > void ofproto_set_flow_restore_wait(bool flow_restore_wait_db);
> > bool ofproto_get_flow_restore_wait(void);
> > +void ofproto_set_lacp_restore_wait(bool lacp_restore_wait_db);
> > +bool ofproto_get_lacp_restore_wait(void);
> > int ofproto_set_stp(struct ofproto *, const struct ofproto_stp_settings *);
> > int ofproto_get_stp_status(struct ofproto *, struct ofproto_stp_status *);
> >
> > diff --git a/utilities/ovs-lib.in b/utilities/ovs-lib.in
> > index dded0b7c7..a845ac915 100644
> > --- a/utilities/ovs-lib.in
> > +++ b/utilities/ovs-lib.in
> > @@ -587,12 +587,21 @@ ovs_save () {
> > [ -z "${bridges}" ] && return 0
> > }
> >
> > +ovs_save_lacp () {
> > + $datadir/scripts/ovs-save save-lacp > "${script_lacp}"
> > + chmod +x "${script_lacp}"
> > +}
> > +
> > save_flows_if_required () {
> > if test X"$DELETE_BRIDGES" != Xyes; then
> > action "Saving flows" ovs_save save-flows "${script_flows}"
> > fi
> > }
> >
> > +save_lacp () {
> > + action "Saving lacp" ovs_save_lacp
> > +}
> > +
> > save_interfaces () {
> > "$datadir/scripts/ovs-save" save-interfaces ${ifaces} \
> > > "${script_interfaces}"
> > @@ -604,6 +613,12 @@ flow_restore_wait () {
> > fi
> > }
> >
> > +lacp_restore_wait () {
> > + if test X"${OVS_VSWITCHD:-yes}" = Xyes; then
> > + ovs_vsctl set open_vswitch . other_config:lacp-restore-wait="true"
> > + fi
> > +}
> > +
> > flow_restore_complete () {
> > if test X"${OVS_VSWITCHD:-yes}" = Xyes; then
> > ovs_vsctl --if-exists remove open_vswitch . other_config \
> > @@ -611,11 +626,23 @@ flow_restore_complete () {
> > fi
> > }
> >
> > +lacp_restore_complete () {
> > + if test X"${OVS_VSWITCHD:-yes}" = Xyes; then
> > + ovs_vsctl --if-exists remove open_vswitch . other_config \
> > + lacp-restore-wait="true"
> > + fi
> > +}
> > +
> > restore_flows () {
> > [ -x "${script_flows}" ] && \
> > action "Restoring saved flows" "${script_flows}"
> > }
> >
> > +restore_lacp () {
> > + [ -x "${script_lacp}" ] && \
> > + action "Restoring saved lacp" "${script_lacp}"
> > +}
> > +
> > restore_interfaces () {
> > [ ! -x "${script_interfaces}" ] && return 0
> > action "Restoring interface configuration" "${script_interfaces}"
> > @@ -633,7 +660,8 @@ restore_interfaces () {
> > init_restore_scripts () {
> > script_interfaces=`mktemp`
> > script_flows=`mktemp`
> > - trap 'rm -f "${script_interfaces}" "${script_flows}"' 0
> > + script_lacp=`mktemp`
> > + trap 'rm -f "${script_interfaces}" "${script_flows}" "${script_lacp}"' > > 0
> > }
> >
> > force_reload_kmod () {
> > @@ -648,6 +676,7 @@ force_reload_kmod () {
> >
> > init_restore_scripts
> > save_flows_if_required
> > + save_lacp
> >
> > # Restart the database first, since a large database may take a
> > # while to load, and we want to minimize forwarding disruption.
> > @@ -682,11 +711,16 @@ force_reload_kmod () {
> >
> > # Start vswitchd by asking it to wait till flow restore is finished.
> > flow_restore_wait
> > + lacp_restore_wait
> > start_forwarding || return 1
> >
> > - # Restore saved flows and inform vswitchd that we are done.
> > + # Restore saved resources and inform vswitchd that we are done.
> > restore_flows
> > + restore_lacp
> > +
> > flow_restore_complete
> > + lacp_restore_complete
> > +
> > add_managers
> >
> > restore_interfaces
> > @@ -704,6 +738,7 @@ restart () {
> > init_restore_scripts
> > if test X"${OVS_VSWITCHD:-yes}" = Xyes; then
> > save_flows_if_required
> > + save_lacp
> > fi
> > fi
> >
> > @@ -716,10 +751,15 @@ restart () {
> >
> > # Start vswitchd by asking it to wait till flow restore is finished.
> > flow_restore_wait
> > + lacp_restore_wait
> > start_forwarding || return 1
> >
> > - # Restore saved flows and inform vswitchd that we are done.
> > + # Restore saved resources and inform vswitchd that we are done.
> > restore_flows
> > + restore_lacp
> > +
> > flow_restore_complete
> > + lacp_restore_complete
> > +
> > add_managers
> > }
> > diff --git a/utilities/ovs-save b/utilities/ovs-save
> > index 67092ecf7..792d5daee 100755
> > --- a/utilities/ovs-save
> > +++ b/utilities/ovs-save
> > @@ -33,6 +33,8 @@ Commands:
> > configuration.
> > save-flows Outputs a shell script on stdout that will restore
> > OpenFlow flows of each Open vSwitch bridge.
> > + save-lacp Outputs a shell script on stdout that will restore
> > + lacp info of each lacp bond port.
> > This script is meant as a helper for the Open vSwitch init script commands.
> > EOF
> > }
> > @@ -159,6 +161,158 @@ save_flows () {
> > echo "rm -rf \"$workdir\""
> > }
> >
> > +save_lacp () {
> > + if (ovs-appctl --version) > /dev/null 2>&1; then :; else
> > + echo "$0: ovs-ofctl not found in $PATH" >&2
> > + exit 1
> > + fi
> > +
> > + case `ovs-appctl version | sed 1q` in
> > + "ovs-vswitchd (Open vSwitch) 1."*.*)
> > + return
> > + ;;
> > + esac
> > +
> > + SP="[[:space:]]*"
> > + BOND_NAME_PATTERN="s/^----${SP}([^[:space:]]+)${SP}----.*/\1/"
> > + STATUS_PATTERN="s/^status:${SP}(.*)/\1/"
> > + SYS_ID_PATTERN="s/^sys_id:${SP}(.*)/\1/"
> > + SYS_PRIORITY_PATTERN="s/^sys_priority:${SP}(.*)/\1/"
> > + AGGREGATION_KEY_PATTERN="s/^aggregation${SP}key:${SP}(.*)/\1/"
> > + LACP_TIME_PATTERN="s/^lacp_time:${SP}(.*)/\1/"
> > + MEMBER_PATTERN="s/^(member|slave):${SP}([^:]+):${SP}(.*)/\2/"
> > + MEMBER_STATUS_PATTERN="s/^(member|slave):${SP}([^:]+):${SP}(.*)/\3/"
> > + PORT_ID_PATTERN="s/^port_id:${SP}(.*)/\1/"
> > + PORT_PRIORITY_PATTERN="s/^port_priority:${SP}(.*)/\1/"
> > + MAY_ENABLE_PATTERN="s/^may_enable:${SP}(.*)/\1/"
> > + ACTOR_SYS_ID_PATTERN="s/^actor${SP}sys_id:${SP}(.*)/\1/"
> > + ACTOR_SYS_PRIORITY_PATTERN="s/^actor${SP}sys_priority:${SP}(.*)/\1/"
> > + ACTOR_PORT_ID_PATTERN="s/^actor${SP}port_id:${SP}(.*)/\1/"
> > + ACTOR_PORT_PRIORITY_PATTERN="s/^actor${SP}port_priority:${SP}(.*)/\1/"
> > + ACTOR_KEY_PATTERN="s/^actor${SP}key:${SP}(.*)/\1/"
> > + ACTOR_STATE_PATTERN="s/^actor${SP}state:${SP}(.*)/\1/"
> > + PARTNER_SYS_ID_PATTERN="s/^partner${SP}sys_id:${SP}(.*)/\1/"
> > +
> > PARTNER_SYS_PRIORITY_PATTERN="s/^partner${SP}sys_priority:${SP}(.*)/\1/"
> > + PARTNER_PORT_ID_PATTERN="s/^partner${SP}port_id:${SP}(.*)/\1/"
> > +
> > PARTNER_PORT_PRIORITY_PATTERN="s/^partner${SP}port_priority:${SP}(.*)/\1/"
> > + PARTNER_KEY_PATTERN="s/^partner${SP}key:${SP}(.*)/\1/"
> > + PARTNER_STATE_PATTERN="s/^partner${SP}state:${SP}(.*)/\1/"
> > + tmpfile=$(mktemp)
> > + ovs-appctl lacp/show | while IFS= read -r line; do
> > + t=$(echo "$line" | sed -E 's/^[[:space:]]+//')
> > + case "$t" in
> > + ----*----*)
> > + BOND_NAME=$(echo "$t" | sed -E "$BOND_NAME_PATTERN")
> > + ;;
> > + status:${SP})
> > + STATUS=$(echo "$t" | sed -E "$STATUS_PATTERN" | sed 's/
> > /+/g')
> > + ;;
> > + sys_id:${SP})
> > + SYS_ID=$(echo "$t" | sed -E "$SYS_ID_PATTERN")
> > + ;;
> > + sys_priority:${SP})
> > + SYS_PRIORITY=$(echo "$t" | sed -E "$SYS_PRIORITY_PATTERN")
> > + ;;
> > + aggregation${SP}key:${SP})
> > + AGGREGATION_KEY=$(echo "$t" |
> > + sed -E "$AGGREGATION_KEY_PATTERN")
> > + ;;
> > + lacp_time:${SP})
> > + LACP_TIME=$(echo "$t" | sed -E "$LACP_TIME_PATTERN")
> > + cmd="ovs-appctl lacp/set $BOND_NAME port status=$STATUS,"
> > + cmd="${cmd}sys_id=$SYS_ID,sys_priority=$SYS_PRIORITY,"
> > + cmd="${cmd}key=$AGGREGATION_KEY,lacp_time=$LACP_TIME"
> > + echo "$cmd" >> "$tmpfile"
> > + ;;
> > + member:${SP}|slave:${SP})
> > + # Extract member name and status
> > + MEMBER_NAME=$(echo "$t" | sed -E "$MEMBER_PATTERN")
> > + MEMBER_STATUS=$(echo "$t" |
> > + sed -E "$MEMBER_STATUS_PATTERN" | sed 's/ /+/g')
> > + ;;
> > + port_id:${SP})
> > + PORT_ID=$(echo "$t" | sed -E "$PORT_ID_PATTERN")
> > + ;;
> > + port_priority:${SP})
> > + PORT_PRIORITY=$(echo "$t" | sed -E
> > "$PORT_PRIORITY_PATTERN")
> > + ;;
> > + may_enable:${SP})
> > + MAY_ENABLE=$(echo "$t" | sed -E "$MAY_ENABLE_PATTERN")
> > + # Print member information
> > + cmd="ovs-appctl lacp/set $BOND_NAME member $MEMBER_NAME
> > member"
> > + cmd="${cmd} status=$MEMBER_STATUS,port_id=$PORT_ID,"
> > +
> > cmd="${cmd}port_priority=$PORT_PRIORITY,may_enable=$MAY_ENABLE"
> > + echo "$cmd" >> "$tmpfile"
> > + ;;
> > + actor${SP}sys_id:${SP})
> > + ACTOR_SYS_ID=$(echo "$t" | sed -E "$ACTOR_SYS_ID_PATTERN")
> > + ;;
> > + actor${SP}sys_priority:${SP})
> > + ACTOR_SYS_PRIORITY=$(echo "$t" |
> > + sed -E "$ACTOR_SYS_PRIORITY_PATTERN")
> > + ;;
> > + actor${SP}port_id:${SP})
> > + ACTOR_PORT_ID=$(echo "$t" | sed -E
> > "$ACTOR_PORT_ID_PATTERN")
> > + ;;
> > + actor${SP}port_priority:${SP})
> > + ACTOR_PORT_PRIORITY=$(echo "$t" |
> > + sed -E "$ACTOR_PORT_PRIORITY_PATTERN")
> > + ;;
> > + actor${SP}key:${SP})
> > + ACTOR_KEY=$(echo "$t" | sed -E "$ACTOR_KEY_PATTERN")
> > + ;;
> > + actor${SP}state:${SP})
> > + ACTOR_STATE=$(echo "$t" |
> > + sed -E "$ACTOR_STATE_PATTERN" | sed 's/ /+/g')
> > + # Print actor information
> > + cmd="ovs-appctl lacp/set $BOND_NAME member $MEMBER_NAME
> > actor"
> > + cmd="${cmd} sys_id=$ACTOR_SYS_ID,"
> > + cmd="${cmd}sys_priority=$ACTOR_SYS_PRIORITY,"
> > + cmd="${cmd}port_id=$ACTOR_PORT_ID,"
> > + cmd="${cmd}port_priority=$ACTOR_PORT_PRIORITY,"
> > + cmd="${cmd}key=$ACTOR_KEY,state=$ACTOR_STATE"
> > + echo "$cmd" >> "$tmpfile"
> > + ;;
> > + partner${SP}sys_id:${SP})
> > + PARTNER_SYS_ID=$(echo "$t" |
> > + sed -E "$PARTNER_SYS_ID_PATTERN")
> > + ;;
> > + partner${SP}sys_priority:${SP})
> > + PARTNER_SYS_PRIORITY=$(echo "$t" |
> > + sed -E "$PARTNER_SYS_PRIORITY_PATTERN")
> > + ;;
> > + partner${SP}port_id:${SP})
> > + PARTNER_PORT_ID=$(echo "$t" |
> > + sed -E "$PARTNER_PORT_ID_PATTERN")
> > + ;;
> > + partner${SP}port_priority:${SP})
> > + PARTNER_PORT_PRIORITY=$(echo "$t" |
> > + sed -E "$PARTNER_PORT_PRIORITY_PATTERN")
> > + ;;
> > + partner${SP}key:${SP})
> > + PARTNER_KEY=$(echo "$t" | sed -E "$PARTNER_KEY_PATTERN")
> > + ;;
> > + partner${SP}state:${SP})
> > + PARTNER_STATE=$(echo "$t" |
> > + sed -E "$PARTNER_STATE_PATTERN" | sed 's/ /+/g')
> > + # Print partner information
> > + cmd="ovs-appctl lacp/set $BOND_NAME"
> > + cmd="${cmd} member $MEMBER_NAME partner"
> > + cmd="${cmd} sys_id=$PARTNER_SYS_ID,"
> > + cmd="${cmd}sys_priority=$PARTNER_SYS_PRIORITY,"
> > + cmd="${cmd}port_id=$PARTNER_PORT_ID,"
> > + cmd="${cmd}port_priority=$PARTNER_PORT_PRIORITY,"
> > + cmd="${cmd}key=$PARTNER_KEY,state=$PARTNER_STATE"
> > + echo "$cmd" >> "$tmpfile"
> > + ;;
> > + esac
> > + done
> > + sed -i '1!G;h;$!d' "$tmpfile"
> > + cat "$tmpfile"
> > + rm -f "$tmpfile"
> > +}
> > +
> > +
> > while [ $# -ne 0 ]
> > do
> > case $1 in
> > @@ -172,6 +326,11 @@ do
> > save_interfaces "$@"
> > exit 0
> > ;;
> > + "save-lacp")
> > + shift
> > + save_lacp "$@"
> > + exit 0
> > + ;;
> > -h | --help)
> > usage
> > exit 0
> > diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> > index 456b784c0..e2c523051 100644
> > --- a/vswitchd/bridge.c
> > +++ b/vswitchd/bridge.c
> > @@ -3415,6 +3415,11 @@ bridge_run(void)
> > "flow-restore-wait", false));
> > }
> >
> > + if (cfg && ofproto_get_lacp_restore_wait()) {
> > + ofproto_set_lacp_restore_wait(smap_get_bool(&cfg->other_config,
> > + "lacp-restore-wait", false));
> > + }
> > +
> > bridge_run__();
> >
> > /* Re-configure SSL/TLS. We do this on every trip through the main
> > loop,
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev