X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fcfm.c;h=6a173a70915c1b1c1bd9a2e083ecf3ace1d42e61;hb=88bf179aa3f3fa89822edcd9b882e0f06d39bf08;hp=8ba0c44773c3d23e769ac6d25c718f75802ae100;hpb=f23d157c05649d369c5456e9a18bb47716306893;p=sliver-openvswitch.git diff --git a/lib/cfm.c b/lib/cfm.c index 8ba0c4477..6a173a709 100644 --- a/lib/cfm.c +++ b/lib/cfm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2010, 2011, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,9 +130,13 @@ struct cfm { atomic_bool check_tnl_key; /* Verify the tunnel key of inbound packets? */ atomic_bool extended; /* Extended mode. */ - atomic_int ref_cnt; + struct ovs_refcount ref_cnt; uint64_t flap_count; /* Count the flaps since boot. */ + + /* True when the variables returned by cfm_get_*() are changed + * since last check. */ + bool status_changed; }; /* Remote MPs represent foreign network entities that are configured to have @@ -236,7 +240,7 @@ static int ccm_interval_to_ms(uint8_t interval) { switch (interval) { - case 0: NOT_REACHED(); /* Explicitly not supported by 802.1ag. */ + case 0: OVS_NOT_REACHED(); /* Explicitly not supported by 802.1ag. */ case 1: return 3; /* Not recommended due to timer resolution. */ case 2: return 10; /* Not recommended due to timer resolution. */ case 3: return 100; @@ -244,10 +248,10 @@ ccm_interval_to_ms(uint8_t interval) case 5: return 10000; case 6: return 60000; case 7: return 600000; - default: NOT_REACHED(); /* Explicitly not supported by 802.1ag. */ + default: OVS_NOT_REACHED(); /* Explicitly not supported by 802.1ag. */ } - NOT_REACHED(); + OVS_NOT_REACHED(); } static long long int @@ -285,7 +289,7 @@ ms_to_ccm_interval(int interval_ms) static uint32_t hash_mpid(uint64_t mpid) { - return hash_bytes(&mpid, sizeof mpid, 0); + return hash_uint64(mpid); } static bool @@ -337,12 +341,13 @@ cfm_create(const struct netdev *netdev) OVS_EXCLUDED(mutex) cfm->flap_count = 0; atomic_init(&cfm->extended, false); atomic_init(&cfm->check_tnl_key, false); - atomic_init(&cfm->ref_cnt, 1); + ovs_refcount_init(&cfm->ref_cnt); ovs_mutex_lock(&mutex); cfm_generate_maid(cfm); hmap_insert(all_cfms, &cfm->hmap_node, hash_string(cfm->name, 0)); ovs_mutex_unlock(&mutex); + return cfm; } @@ -350,15 +355,12 @@ void cfm_unref(struct cfm *cfm) OVS_EXCLUDED(mutex) { struct remote_mp *rmp, *rmp_next; - int orig; if (!cfm) { return; } - atomic_sub(&cfm->ref_cnt, 1, &orig); - ovs_assert(orig > 0); - if (orig != 1) { + if (ovs_refcount_unref(&cfm->ref_cnt) != 1) { return; } @@ -374,6 +376,7 @@ cfm_unref(struct cfm *cfm) OVS_EXCLUDED(mutex) hmap_destroy(&cfm->remote_mps); netdev_close(cfm->netdev); free(cfm->rmps_array); + free(cfm); } @@ -382,13 +385,19 @@ cfm_ref(const struct cfm *cfm_) { struct cfm *cfm = CONST_CAST(struct cfm *, cfm_); if (cfm) { - int orig; - atomic_add(&cfm->ref_cnt, 1, &orig); - ovs_assert(orig > 0); + ovs_refcount_ref(&cfm->ref_cnt); } return cfm; } +/* Records the status change and changes the global connectivity seq. */ +static void +cfm_status_changed(struct cfm *cfm) OVS_REQUIRES(mutex) +{ + seq_change(connectivity_seq_get()); + cfm->status_changed = true; +} + /* Should be run periodically to update fault statistics messages. */ void cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) @@ -397,7 +406,11 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) if (timer_expired(&cfm->fault_timer)) { long long int interval = cfm_fault_interval(cfm); struct remote_mp *rmp, *rmp_next; - bool old_cfm_fault = cfm->fault; + enum cfm_fault_reason old_cfm_fault = cfm->fault; + uint64_t old_flap_count = cfm->flap_count; + int old_health = cfm->health; + size_t old_rmps_array_len = cfm->rmps_array_len; + bool old_rmps_deleted = false; bool old_rmp_opup = cfm->remote_opup; bool demand_override; bool rmp_set_opup = false; @@ -423,7 +436,6 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) cfm->health = 0; } else { int exp_ccm_recvd; - int old_health = cfm->health; rmp = CONTAINER_OF(hmap_first(&cfm->remote_mps), struct remote_mp, node); @@ -438,10 +450,6 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) cfm->health = MIN(cfm->health, 100); rmp->num_health_ccm = 0; ovs_assert(cfm->health >= 0 && cfm->health <= 100); - - if (cfm->health != old_health) { - seq_change(connectivity_seq_get()); - } } cfm->health_interval = 0; } @@ -461,6 +469,7 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) " %lldms", cfm->name, rmp->mpid, time_msec() - rmp->last_rx); if (!demand_override) { + old_rmps_deleted = true; hmap_remove(&cfm->remote_mps, &rmp->node); free(rmp); } @@ -484,10 +493,6 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) cfm->remote_opup = true; } - if (old_rmp_opup != cfm->remote_opup) { - seq_change(connectivity_seq_get()); - } - if (hmap_is_empty(&cfm->remote_mps)) { cfm->fault |= CFM_FAULT_RECV; } @@ -506,11 +511,19 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) } /* If there is a flap, increments the counter. */ - if (old_cfm_fault == false || cfm->fault == false) { + if (old_cfm_fault == 0 || cfm->fault == 0) { cfm->flap_count++; } + } - seq_change(connectivity_seq_get()); + /* These variables represent the cfm session status, it is desirable + * to update them to database immediately after change. */ + if (old_health != cfm->health + || old_rmp_opup != cfm->remote_opup + || (old_rmps_array_len != cfm->rmps_array_len || old_rmps_deleted) + || old_cfm_fault != cfm->fault + || old_flap_count != cfm->flap_count) { + cfm_status_changed(cfm); } cfm->booted = true; @@ -554,10 +567,10 @@ cfm_compose_ccm(struct cfm *cfm, struct ofpbuf *packet, if (ccm_vlan || cfm->ccm_pcp) { uint16_t tci = ccm_vlan | (cfm->ccm_pcp << VLAN_PCP_SHIFT); - eth_push_vlan(packet, htons(tci)); + eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(tci)); } - ccm = packet->l3; + ccm = ofpbuf_l3(packet); ccm->mdlevel_version = 0; ccm->opcode = CCM_OPCODE; ccm->tlv_offset = 70; @@ -718,8 +731,9 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) ovs_mutex_lock(&mutex); - eth = p->l2; - ccm = ofpbuf_at(p, (uint8_t *)p->l3 - (uint8_t *)p->data, CCM_ACCEPT_LEN); + eth = ofpbuf_l2(p); + ccm = ofpbuf_at(p, (uint8_t *)ofpbuf_l3(p) - (uint8_t *)ofpbuf_data(p), + CCM_ACCEPT_LEN); if (!ccm) { VLOG_INFO_RL(&rl, "%s: Received an unparseable 802.1ag CCM heartbeat.", @@ -835,6 +849,20 @@ out: ovs_mutex_unlock(&mutex); } +/* Returns and resets the 'cfm->status_changed'. */ +bool +cfm_check_status_change(struct cfm *cfm) OVS_EXCLUDED(mutex) +{ + bool ret; + + ovs_mutex_lock(&mutex); + ret = cfm->status_changed; + cfm->status_changed = false; + ovs_mutex_unlock(&mutex); + + return ret; +} + static int cfm_get_fault__(const struct cfm *cfm) OVS_REQUIRES(mutex) { @@ -1028,9 +1056,11 @@ cfm_unixctl_set_fault(struct unixctl_conn *conn, int argc, const char *argv[], goto out; } cfm->fault_override = fault_override; + cfm_status_changed(cfm); } else { HMAP_FOR_EACH (cfm, hmap_node, all_cfms) { cfm->fault_override = fault_override; + cfm_status_changed(cfm); } }