+/* Remote MPs represent foreign network entities that are configured to have
+ * the same MAID as this CFM instance. */
+struct remote_mp {
+ uint64_t mpid; /* The Maintenance Point ID of this 'remote_mp'. */
+ struct hmap_node node; /* Node in 'remote_mps' map. */
+
+ bool recv; /* CCM was received since last fault check. */
+ bool opup; /* Operational State. */
+ uint32_t seq; /* Most recently received sequence number. */
+ uint8_t num_health_ccm; /* Number of received ccm frames every
+ CFM_HEALTH_INTERVAL * 'fault_interval'. */
+ long long int last_rx; /* Last CCM reception time. */
+
+};
+
+static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 30);
+
+static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
+static struct hmap all_cfms__ = HMAP_INITIALIZER(&all_cfms__);
+static struct hmap *const all_cfms OVS_GUARDED_BY(mutex) = &all_cfms__;
+
+static unixctl_cb_func cfm_unixctl_show;
+static unixctl_cb_func cfm_unixctl_set_fault;
+
+static uint64_t
+cfm_rx_packets(const struct cfm *cfm) OVS_REQUIRES(mutex)
+{
+ struct netdev_stats stats;
+
+ if (!netdev_get_stats(cfm->netdev, &stats)) {
+ return stats.rx_packets;
+ } else {
+ return 0;
+ }
+}
+
+static const uint8_t *
+cfm_ccm_addr(struct cfm *cfm)
+{
+ bool extended;
+ atomic_read(&cfm->extended, &extended);
+ return extended ? eth_addr_ccm_x : eth_addr_ccm;
+}
+
+/* Returns the string representation of the given cfm_fault_reason 'reason'. */
+const char *
+cfm_fault_reason_to_str(int reason)
+{
+ switch (reason) {
+#define CFM_FAULT_REASON(NAME, STR) case CFM_FAULT_##NAME: return #STR;
+ CFM_FAULT_REASONS
+#undef CFM_FAULT_REASON
+ default: return "<unknown>";
+ }
+}
+
+static void
+ds_put_cfm_fault(struct ds *ds, int fault)
+{
+ int i;
+
+ for (i = 0; i < CFM_FAULT_N_REASONS; i++) {
+ int reason = 1 << i;
+
+ if (fault & reason) {
+ ds_put_format(ds, "%s ", cfm_fault_reason_to_str(reason));
+ }
+ }
+
+ ds_chomp(ds, ' ');
+}
+
+static void
+cfm_generate_maid(struct cfm *cfm) OVS_REQUIRES(mutex)
+{
+ const char *ovs_md_name = "ovs";
+ const char *ovs_ma_name = "ovs";
+ uint8_t *ma_p;
+ size_t md_len, ma_len;
+
+ memset(cfm->maid, 0, CCM_MAID_LEN);
+
+ md_len = strlen(ovs_md_name);
+ ma_len = strlen(ovs_ma_name);
+
+ ovs_assert(md_len && ma_len && md_len + ma_len + 4 <= CCM_MAID_LEN);
+
+ cfm->maid[0] = 4; /* MD name string format. */
+ cfm->maid[1] = md_len; /* MD name size. */
+ memcpy(&cfm->maid[2], ovs_md_name, md_len); /* MD name. */
+
+ ma_p = cfm->maid + 2 + md_len;
+ ma_p[0] = 2; /* MA name string format. */
+ ma_p[1] = ma_len; /* MA name size. */
+ memcpy(&ma_p[2], ovs_ma_name, ma_len); /* MA name. */
+}
+