X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fcfm.c;h=1b326252902c21b98f644fc247f317ec9b9d23db;hb=HEAD;hp=9c65b3489ddae24897b49aa23369fa73b224ef4e;hpb=fb668e3a13eaa07bbb8bc50cbee1d201051b779c;p=sliver-openvswitch.git diff --git a/lib/cfm.c b/lib/cfm.c index 9c65b3489..1b3262529 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. @@ -22,6 +22,7 @@ #include #include "byte-order.h" +#include "connectivity.h" #include "dynamic-string.h" #include "flow.h" #include "hash.h" @@ -31,6 +32,7 @@ #include "packets.h" #include "poll-loop.h" #include "random.h" +#include "seq.h" #include "timer.h" #include "timeval.h" #include "unixctl.h" @@ -128,9 +130,18 @@ 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; + + /* When 'cfm->demand' is set, at least one ccm is required to be received + * every 100 * cfm_interval. If ccm is not received within this interval, + * even if data packets are received, the cfm fault will be set. */ + struct timer demand_rx_ccm_t; }; /* Remote MPs represent foreign network entities that are configured to have @@ -234,7 +245,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; @@ -242,10 +253,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 @@ -283,7 +294,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 @@ -335,12 +346,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; } @@ -348,15 +360,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; } @@ -372,6 +381,7 @@ cfm_unref(struct cfm *cfm) OVS_EXCLUDED(mutex) hmap_destroy(&cfm->remote_mps); netdev_close(cfm->netdev); free(cfm->rmps_array); + free(cfm); } @@ -380,13 +390,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) @@ -395,7 +411,12 @@ 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; bool rmp_set_opdown = false; @@ -443,7 +464,8 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex) if (cfm->demand) { uint64_t rx_packets = cfm_rx_packets(cfm); demand_override = hmap_count(&cfm->remote_mps) == 1 - && rx_packets > cfm->rx_packets; + && rx_packets > cfm->rx_packets + && !timer_expired(&cfm->demand_rx_ccm_t); cfm->rx_packets = rx_packets; } @@ -453,6 +475,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); } @@ -494,11 +517,21 @@ 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++; } } + /* 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; timer_set_duration(&cfm->fault_timer, interval); VLOG_DBG("%s: new fault interval", cfm->name); @@ -540,10 +573,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; @@ -704,8 +737,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.", @@ -808,6 +842,10 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) rmp->mpid = ccm_mpid; if (!cfm_fault) { rmp->num_health_ccm++; + if (cfm->demand) { + timer_set_duration(&cfm->demand_rx_ccm_t, + 100 * cfm->ccm_interval_ms); + } } rmp->recv = true; cfm->recv_fault |= cfm_fault; @@ -821,6 +859,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) { @@ -1014,9 +1066,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); } }