From 30618594b6c68497b56443de81a7f19e57e3e898 Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Thu, 1 Aug 2013 18:04:07 -0700 Subject: [PATCH] mac-learning: Stop using tags. This patch transitions mac learning away from using tags as required by future patches. Signed-off-by: Ethan Jackson Acked-by: Ben Pfaff --- lib/learning-switch.c | 9 +++--- lib/mac-learning.c | 60 ++++++++++++------------------------ lib/mac-learning.h | 22 +++---------- ofproto/ofproto-dpif-xlate.c | 9 +++--- ofproto/ofproto-dpif.c | 23 ++++++++------ 5 files changed, 45 insertions(+), 78 deletions(-) diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 6c8156ace..9c1aff7a4 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -252,7 +252,7 @@ lswitch_run(struct lswitch *sw) if (sw->ml) { ovs_rwlock_wrlock(&sw->ml->rwlock); - mac_learning_run(sw->ml, NULL); + mac_learning_run(sw->ml); ovs_rwlock_unlock(&sw->ml->rwlock); } @@ -479,14 +479,13 @@ lswitch_choose_destination(struct lswitch *sw, const struct flow *flow) ovs_rwlock_wrlock(&sw->ml->rwlock); if (mac_learning_may_learn(sw->ml, flow->dl_src, 0)) { struct mac_entry *mac = mac_learning_insert(sw->ml, flow->dl_src, 0); - if (mac_entry_is_new(mac) - || mac->port.ofp_port != flow->in_port.ofp_port) { + if (mac->port.ofp_port != flow->in_port.ofp_port) { VLOG_DBG_RL(&rl, "%016llx: learned that "ETH_ADDR_FMT" is on " "port %"PRIu16, sw->datapath_id, ETH_ADDR_ARGS(flow->dl_src), flow->in_port.ofp_port); mac->port.ofp_port = flow->in_port.ofp_port; - mac_learning_changed(sw->ml, mac); + mac_learning_changed(sw->ml); } } ovs_rwlock_unlock(&sw->ml->rwlock); @@ -501,7 +500,7 @@ lswitch_choose_destination(struct lswitch *sw, const struct flow *flow) struct mac_entry *mac; ovs_rwlock_rdlock(&sw->ml->rwlock); - mac = mac_learning_lookup(sw->ml, flow->dl_dst, 0, NULL); + mac = mac_learning_lookup(sw->ml, flow->dl_dst, 0); if (mac) { out_port = mac->port.ofp_port; if (out_port == flow->in_port.ofp_port) { diff --git a/lib/mac-learning.c b/lib/mac-learning.c index 06e61d1d3..80dac6982 100644 --- a/lib/mac-learning.c +++ b/lib/mac-learning.c @@ -25,7 +25,6 @@ #include "hash.h" #include "list.h" #include "poll-loop.h" -#include "tag.h" #include "timeval.h" #include "unaligned.h" #include "util.h" @@ -60,16 +59,6 @@ mac_entry_from_lru_node(struct list *list) return CONTAINER_OF(list, struct mac_entry, lru_node); } -/* Returns a tag that represents that 'mac' is on an unknown port in 'vlan'. - * (When we learn where 'mac' is in 'vlan', this allows flows that were - * flooded to be revalidated.) */ -static tag_type -make_unknown_mac_tag(const struct mac_learning *ml, - const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan) -{ - return tag_create_deterministic(mac_table_hash(ml, mac, vlan)); -} - static struct mac_entry * mac_entry_lookup(const struct mac_learning *ml, const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan) @@ -124,7 +113,7 @@ mac_learning_create(unsigned int idle_time) ml->flood_vlans = NULL; ml->idle_time = normalize_idle_time(idle_time); ml->max_entries = MAC_DEFAULT_MAX; - tag_set_init(&ml->tags); + ml->need_revalidate = false; atomic_init(&ml->ref_cnt, 1); ovs_rwlock_init(&ml->rwlock); return ml; @@ -257,8 +246,8 @@ mac_learning_insert(struct mac_learning *ml, hmap_insert(&ml->table, &e->hmap_node, hash); memcpy(e->mac, src_mac, ETH_ADDR_LEN); e->vlan = vlan; - e->tag = 0; e->grat_arp_lock = TIME_MIN; + e->port.p = NULL; } else { list_remove(&e->lru_node); } @@ -279,14 +268,10 @@ mac_learning_insert(struct mac_learning *ml, * from mac_learning_insert(), if the entry is either new or if its learned * port has changed. */ void -mac_learning_changed(struct mac_learning *ml, struct mac_entry *e) +mac_learning_changed(struct mac_learning *ml) { - tag_type tag = e->tag ? e->tag : make_unknown_mac_tag(ml, e->mac, e->vlan); - COVERAGE_INC(mac_learning_learned); - - e->tag = tag_create_random(); - tag_set_add(&ml->tags, tag); + ml->need_revalidate = true; } /* Looks up MAC 'dst' for VLAN 'vlan' in 'ml' and returns the associated MAC @@ -295,8 +280,7 @@ mac_learning_changed(struct mac_learning *ml, struct mac_entry *e) * '*tag'. */ struct mac_entry * mac_learning_lookup(const struct mac_learning *ml, - const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan, - tag_type *tag) + const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan) { if (eth_addr_is_multicast(dst)) { /* No tag because the treatment of multicast destinations never @@ -309,11 +293,7 @@ mac_learning_lookup(const struct mac_learning *ml, } else { struct mac_entry *e = mac_entry_lookup(ml, dst, vlan); - ovs_assert(e == NULL || e->tag != 0); - if (tag) { - /* Tag either the learned port or the lack thereof. */ - *tag |= e ? e->tag : make_unknown_mac_tag(ml, dst, vlan); - } + ovs_assert(e == NULL || e->port.p != NULL) return e; } } @@ -332,44 +312,42 @@ mac_learning_expire(struct mac_learning *ml, struct mac_entry *e) * is responsible for revalidating any flows that depend on 'ml', if * necessary. */ void -mac_learning_flush(struct mac_learning *ml, struct tag_set *tags) +mac_learning_flush(struct mac_learning *ml) { struct mac_entry *e; while (get_lru(ml, &e)){ - if (tags) { - tag_set_add(tags, e->tag); - } + ml->need_revalidate = true; mac_learning_expire(ml, e); } hmap_shrink(&ml->table); } -void -mac_learning_run(struct mac_learning *ml, struct tag_set *set) +/* Does periodic work required by 'ml'. Returns true if something changed that + * may require flow revalidation. */ +bool +mac_learning_run(struct mac_learning *ml) { + bool need_revalidate; struct mac_entry *e; - if (set) { - tag_set_union(set, &ml->tags); - } - tag_set_init(&ml->tags); - while (get_lru(ml, &e) && (hmap_count(&ml->table) > ml->max_entries || time_now() >= e->expires)) { COVERAGE_INC(mac_learning_expired); - if (set) { - tag_set_add(set, e->tag); - } + ml->need_revalidate = true; mac_learning_expire(ml, e); } + + need_revalidate = ml->need_revalidate; + ml->need_revalidate = false; + return need_revalidate; } void mac_learning_wait(struct mac_learning *ml) { if (hmap_count(&ml->table) > ml->max_entries - || !tag_set_is_empty(&ml->tags)) { + || ml->need_revalidate) { poll_immediate_wake(); } else if (!list_is_empty(&ml->lrus)) { struct mac_entry *e = mac_entry_from_lru_node(ml->lrus.next); diff --git a/lib/mac-learning.h b/lib/mac-learning.h index ea5ea8a58..ba7f73421 100644 --- a/lib/mac-learning.h +++ b/lib/mac-learning.h @@ -23,7 +23,6 @@ #include "ovs-atomic.h" #include "ovs-thread.h" #include "packets.h" -#include "tag.h" #include "timeval.h" struct mac_learning; @@ -46,7 +45,6 @@ struct mac_entry { time_t grat_arp_lock; /* Gratuitous ARP lock expiration time. */ uint8_t mac[ETH_ADDR_LEN]; /* Known MAC address. */ uint16_t vlan; /* VLAN tag. */ - tag_type tag; /* Tag for this learning entry. */ /* The following are marked guarded to prevent users from iterating over or * accessing a mac_entry without hodling the parent mac_learning rwlock. */ @@ -59,13 +57,6 @@ struct mac_entry { } port OVS_GUARDED; }; -/* Returns true if mac_learning_insert() just created 'mac' and the caller has - * not yet properly initialized it. */ -static inline bool mac_entry_is_new(const struct mac_entry *mac) -{ - return !mac->tag; -} - /* Sets a gratuitous ARP lock on 'mac' that will expire in * MAC_GRAT_ARP_LOCK_TIME seconds. */ static inline void mac_entry_set_grat_arp_lock(struct mac_entry *mac) @@ -89,9 +80,9 @@ struct mac_learning { unsigned long *flood_vlans; /* Bitmap of learning disabled VLANs. */ unsigned int idle_time; /* Max age before deleting an entry. */ size_t max_entries; /* Max number of learned MACs. */ - struct tag_set tags; /* Tags which have changed. */ atomic_int ref_cnt; struct ovs_rwlock rwlock; + bool need_revalidate; }; int mac_entry_age(const struct mac_learning *ml, const struct mac_entry *e) @@ -102,8 +93,7 @@ struct mac_learning *mac_learning_create(unsigned int idle_time); struct mac_learning *mac_learning_ref(const struct mac_learning *); void mac_learning_unref(struct mac_learning *); -void mac_learning_run(struct mac_learning *ml, struct tag_set *) - OVS_REQ_WRLOCK(ml->rwlock); +bool mac_learning_run(struct mac_learning *ml) OVS_REQ_WRLOCK(ml->rwlock); void mac_learning_wait(struct mac_learning *ml) OVS_REQ_RDLOCK(ml->rwlock); @@ -126,19 +116,17 @@ struct mac_entry *mac_learning_insert(struct mac_learning *ml, const uint8_t src[ETH_ADDR_LEN], uint16_t vlan) OVS_REQ_WRLOCK(ml->rwlock); -void mac_learning_changed(struct mac_learning *ml, struct mac_entry *e) - OVS_REQ_WRLOCK(ml->rwlock); +void mac_learning_changed(struct mac_learning *ml) OVS_REQ_WRLOCK(ml->rwlock); /* Lookup. */ struct mac_entry *mac_learning_lookup(const struct mac_learning *ml, const uint8_t dst[ETH_ADDR_LEN], - uint16_t vlan, tag_type *) + uint16_t vlan) OVS_REQ_RDLOCK(ml->rwlock); /* Flushing. */ void mac_learning_expire(struct mac_learning *ml, struct mac_entry *e) OVS_REQ_WRLOCK(ml->rwlock); -void mac_learning_flush(struct mac_learning *ml, struct tag_set *) - OVS_REQ_WRLOCK(ml->rwlock); +void mac_learning_flush(struct mac_learning *ml) OVS_REQ_WRLOCK(ml->rwlock); #endif /* mac-learning.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 01ce3c698..25c88c1fe 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -853,7 +853,7 @@ update_learning_table(const struct xbridge *xbridge, } } - if (mac_entry_is_new(mac) || mac->port.p != in_xbundle->ofbundle) { + if (mac->port.p != in_xbundle->ofbundle) { /* The log messages here could actually be useful in debugging, * so keep the rate limit relatively high. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300); @@ -863,7 +863,7 @@ update_learning_table(const struct xbridge *xbridge, in_xbundle->name, vlan); mac->port.p = in_xbundle->ofbundle; - mac_learning_changed(xbridge->ml, mac); + mac_learning_changed(xbridge->ml); } out: ovs_rwlock_unlock(&xbridge->ml->rwlock); @@ -912,7 +912,7 @@ is_admissible(struct xlate_ctx *ctx, struct xport *in_port, case BV_DROP_IF_MOVED: ovs_rwlock_rdlock(&xbridge->ml->rwlock); - mac = mac_learning_lookup(xbridge->ml, flow->dl_src, vlan, NULL); + mac = mac_learning_lookup(xbridge->ml, flow->dl_src, vlan); if (mac && mac->port.p != in_xbundle->ofbundle && (!is_gratuitous_arp(flow, &ctx->xout->wc) || mac_entry_is_grat_arp_locked(mac))) { @@ -998,8 +998,7 @@ xlate_normal(struct xlate_ctx *ctx) /* Determine output bundle. */ ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock); - mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan, - &ctx->xout->tags); + mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan); if (mac) { struct xbundle *mac_xbundle = xbundle_lookup(mac->port.p); if (mac_xbundle && mac_xbundle != in_xbundle) { diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 24f66720a..e3c2053a1 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -392,12 +392,14 @@ enum revalidate_reason { REV_STP, /* Spanning tree protocol port status change. */ REV_PORT_TOGGLED, /* Port enabled or disabled by CFM, LACP, ...*/ REV_FLOW_TABLE, /* Flow table changed. */ + REV_MAC_LEARNING, /* Mac learning changed. */ REV_INCONSISTENCY /* Facet self-check failed. */ }; COVERAGE_DEFINE(rev_reconfigure); COVERAGE_DEFINE(rev_stp); COVERAGE_DEFINE(rev_port_toggled); COVERAGE_DEFINE(rev_flow_table); +COVERAGE_DEFINE(rev_mac_learning); COVERAGE_DEFINE(rev_inconsistency); /* Drop keys are odp flow keys which have drop flows installed in the kernel. @@ -768,6 +770,7 @@ type_run(const char *type) case REV_STP: COVERAGE_INC(rev_stp); break; case REV_PORT_TOGGLED: COVERAGE_INC(rev_port_toggled); break; case REV_FLOW_TABLE: COVERAGE_INC(rev_flow_table); break; + case REV_MAC_LEARNING: COVERAGE_INC(rev_mac_learning); break; case REV_INCONSISTENCY: COVERAGE_INC(rev_inconsistency); break; } @@ -1500,7 +1503,7 @@ run(struct ofproto *ofproto_) if (mbridge_need_revalidate(ofproto->mbridge)) { ofproto->backer->need_revalidate = REV_RECONFIGURE; ovs_rwlock_wrlock(&ofproto->ml->rwlock); - mac_learning_flush(ofproto->ml, NULL); + mac_learning_flush(ofproto->ml); ovs_rwlock_unlock(&ofproto->ml->rwlock); } @@ -1533,7 +1536,9 @@ run(struct ofproto *ofproto_) stp_run(ofproto); ovs_rwlock_wrlock(&ofproto->ml->rwlock); - mac_learning_run(ofproto->ml, &ofproto->backer->revalidate_set); + if (mac_learning_run(ofproto->ml)) { + ofproto->backer->need_revalidate = REV_MAC_LEARNING; + } ovs_rwlock_unlock(&ofproto->ml->rwlock); /* Check the consistency of a random facet, to aid debugging. */ @@ -2097,8 +2102,7 @@ update_stp_port_state(struct ofport_dpif *ofport) != stp_learn_in_state(state)) { /* xxx Learning action flows should also be flushed. */ ovs_rwlock_wrlock(&ofproto->ml->rwlock); - mac_learning_flush(ofproto->ml, - &ofproto->backer->revalidate_set); + mac_learning_flush(ofproto->ml); ovs_rwlock_unlock(&ofproto->ml->rwlock); } fwd_change = stp_forward_in_state(ofport->stp_state) @@ -2205,7 +2209,7 @@ stp_run(struct ofproto_dpif *ofproto) if (stp_check_and_reset_fdb_flush(ofproto->stp)) { ovs_rwlock_wrlock(&ofproto->ml->rwlock); - mac_learning_flush(ofproto->ml, &ofproto->backer->revalidate_set); + mac_learning_flush(ofproto->ml); ovs_rwlock_unlock(&ofproto->ml->rwlock); } } @@ -2374,8 +2378,7 @@ bundle_flush_macs(struct ofbundle *bundle, bool all_ofprotos) struct mac_entry *e; ovs_rwlock_wrlock(&o->ml->rwlock); - e = mac_learning_lookup(o->ml, mac->mac, mac->vlan, - NULL); + e = mac_learning_lookup(o->ml, mac->mac, mac->vlan); if (e) { mac_learning_expire(o->ml, e); } @@ -2849,7 +2852,7 @@ set_flood_vlans(struct ofproto *ofproto_, unsigned long *flood_vlans) struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); ovs_rwlock_wrlock(&ofproto->ml->rwlock); if (mac_learning_set_flood_vlans(ofproto->ml, flood_vlans)) { - mac_learning_flush(ofproto->ml, &ofproto->backer->revalidate_set); + mac_learning_flush(ofproto->ml); } ovs_rwlock_unlock(&ofproto->ml->rwlock); return 0; @@ -5785,12 +5788,12 @@ ofproto_unixctl_fdb_flush(struct unixctl_conn *conn, int argc, return; } ovs_rwlock_wrlock(&ofproto->ml->rwlock); - mac_learning_flush(ofproto->ml, &ofproto->backer->revalidate_set); + mac_learning_flush(ofproto->ml); ovs_rwlock_unlock(&ofproto->ml->rwlock); } else { HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) { ovs_rwlock_wrlock(&ofproto->ml->rwlock); - mac_learning_flush(ofproto->ml, &ofproto->backer->revalidate_set); + mac_learning_flush(ofproto->ml); ovs_rwlock_unlock(&ofproto->ml->rwlock); } } -- 2.43.0