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. > 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. > 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
