With this commit, RSTP is able to flush from the MAC learning table entries pertaining to a single port. Before this commit the whole table was flushed every time a port requested flushing actions.
Signed-off-by: Daniele Venturino <daniele.ventur...@m3s.it> --- lib/rstp.c | 52 +++++++++++++++++++++++++++++++++----------------- lib/rstp.h | 2 +- ofproto/ofproto-dpif.c | 18 ++++++++--------- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/lib/rstp.c b/lib/rstp.c index 55c43c0..1ab4938 100644 --- a/lib/rstp.c +++ b/lib/rstp.c @@ -775,31 +775,49 @@ rstp_get_root_path_cost(const struct rstp *rstp) return cost; } -/* Returns true if something has happened to 'rstp' which necessitates - * flushing the client's MAC learning table. +/* Finds a port which needs to flush its own MAC learning table. A NULL pointer + * is returned if no port needs to flush its MAC learning table. */ -bool -rstp_check_and_reset_fdb_flush(struct rstp *rstp) +void * +rstp_check_and_reset_fdb_flush(struct rstp *rstp, struct rstp_port **port) OVS_EXCLUDED(rstp_mutex) { - bool needs_flush; - struct rstp_port *p; - - needs_flush = false; + void *aux = NULL; ovs_mutex_lock(&rstp_mutex); - HMAP_FOR_EACH (p, node, &rstp->ports) { - if (p->fdb_flush) { - needs_flush = true; - /* fdb_flush should be reset by the filtering database - * once the entries are removed if rstp_version is TRUE, and - * immediately if stp_version is TRUE.*/ - p->fdb_flush = false; + if (*port == NULL) { + struct rstp_port *p; + + HMAP_FOR_EACH (p, node, &rstp->ports) { + if (p->fdb_flush) { + aux = p->aux; + *port = p; + goto out; + } } + } else { /* continue */ + struct rstp_port *p = *port; + + HMAP_FOR_EACH_CONTINUE (p, node, &rstp->ports) { + if (p->fdb_flush) { + aux = p->aux; + *port = p; + goto out; + } + } + } + /* No port needs flushing. */ + *port = NULL; +out: + /* fdb_flush should be reset by the filtering database + * once the entries are removed if rstp_version is TRUE, and + * immediately if stp_version is TRUE.*/ + if (*port != NULL) { + (*port)->fdb_flush = false; } ovs_mutex_unlock(&rstp_mutex); - return needs_flush; -} + return aux; + } /* Finds a port whose state has changed, and returns the aux pointer set for * the port. A NULL pointer is returned when no changed port is found. On diff --git a/lib/rstp.h b/lib/rstp.h index b429e35..b05cdf2 100644 --- a/lib/rstp.h +++ b/lib/rstp.h @@ -157,7 +157,7 @@ void rstp_tick_timers(struct rstp *) void rstp_port_received_bpdu(struct rstp_port *, const void *bpdu, size_t bpdu_size) OVS_EXCLUDED(rstp_mutex); -bool rstp_check_and_reset_fdb_flush(struct rstp *) +void *rstp_check_and_reset_fdb_flush(struct rstp *, struct rstp_port **) OVS_EXCLUDED(rstp_mutex); void *rstp_get_next_changed_port_aux(struct rstp *, struct rstp_port **) OVS_EXCLUDED(rstp_mutex); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index dc0ecdf..2fd9896 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -140,6 +140,7 @@ static void bundle_destroy(struct ofbundle *); static void bundle_del_port(struct ofport_dpif *); static void bundle_run(struct ofbundle *); static void bundle_wait(struct ofbundle *); +static void bundle_flush_macs(struct ofbundle *, bool); static void stp_run(struct ofproto_dpif *ofproto); static void stp_wait(struct ofproto_dpif *ofproto); @@ -2098,9 +2099,9 @@ update_rstp_port_state(struct ofport_dpif *ofport) if (rstp_learn_in_state(ofport->rstp_state) != rstp_learn_in_state(state)) { /* xxx Learning action flows should also be flushed. */ - ovs_rwlock_wrlock(&ofproto->ml->rwlock); - mac_learning_flush(ofproto->ml); - ovs_rwlock_unlock(&ofproto->ml->rwlock); + if (ofport->bundle) { + bundle_flush_macs(ofport->bundle, false); + } } fwd_change = rstp_forward_in_state(ofport->rstp_state) != rstp_forward_in_state(state); @@ -2140,16 +2141,13 @@ rstp_run(struct ofproto_dpif *ofproto) while ((ofport = rstp_get_next_changed_port_aux(ofproto->rstp, &rp))) { update_rstp_port_state(ofport); } + rp = NULL; + ofport = NULL; /* FIXME: This check should be done on-event (i.e., when setting * p->fdb_flush) and not periodically. */ - if (rstp_check_and_reset_fdb_flush(ofproto->rstp)) { - ovs_rwlock_wrlock(&ofproto->ml->rwlock); - /* FIXME: RSTP should be able to flush the entries pertaining to a - * single port, not the whole table. - */ - mac_learning_flush(ofproto->ml); - ovs_rwlock_unlock(&ofproto->ml->rwlock); + while ((ofport = rstp_check_and_reset_fdb_flush(ofproto->rstp, &rp))) { + bundle_flush_macs(ofport->bundle, false); } } } -- 1.8.1.2 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev