#include "poll-loop.h"
#include "timer.h"
#include "timeval.h"
+#include "unixctl.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(cfm);
struct cfm_internal {
struct cfm cfm;
- uint32_t seq; /* The sequence number of our last CCM. */
+ struct list list_node; /* Node in all_cfms list. */
+ uint32_t seq; /* The sequence number of our last CCM. */
uint8_t ccm_interval; /* The CCM transmission interval. */
int ccm_interval_ms; /* 'ccm_interval' in milliseconds. */
};
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
+static struct list all_cfms = LIST_INITIALIZER(&all_cfms);
+
+static void cfm_unixctl_show(struct unixctl_conn *, const char *args,
+ void *aux);
static int
ccm_interval_to_ms(uint8_t interval)
return NULL;
}
+void
+cfm_init(void)
+{
+ unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
+}
+
/* Allocates a 'cfm' object. This object should have its 'mpid', 'maid',
* 'eth_src', and 'interval' filled out. cfm_configure() should be called
* whenever changes are made to 'cfm', and before cfm_run() is called for the
cfm = &cfmi->cfm;
hmap_init(&cfm->remote_mps);
+ list_push_back(&all_cfms, &cfmi->list_node);
return cfm;
}
}
hmap_destroy(&cfm->remote_mps);
+ list_remove(&cfmi->list_node);
free(cfmi);
}
}
}
-void
-cfm_dump_ds(const struct cfm *cfm, struct ds *ds)
+static struct cfm_internal *
+cfm_find(const char *name)
{
- const struct cfm_internal *cfmi = cfm_to_internal(cfm);
+ struct cfm_internal *cfmi;
+
+ LIST_FOR_EACH (cfmi, list_node, &all_cfms) {
+ if (cfmi->cfm.name && !strcmp(cfmi->cfm.name, name)) {
+ return cfmi;
+ }
+ }
+ return NULL;
+}
+
+static void
+cfm_unixctl_show(struct unixctl_conn *conn,
+ const char *args, void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ const struct cfm_internal *cfmi;
struct remote_mp *rmp;
- ds_put_format(ds, "MPID %"PRIu16": %s\n", cfm->mpid,
- cfm->fault ? "fault" : "");
+ cfmi = cfm_find(args);
+ if (!cfmi) {
+ unixctl_command_reply(conn, 501, "no such CFM object");
+ return;
+ }
- ds_put_format(ds, "\tinterval: %dms\n", cfmi->ccm_interval_ms);
- ds_put_format(ds, "\tnext CCM tx: %lldms\n",
+ ds_put_format(&ds, "MPID %"PRIu16": %s\n", cfmi->cfm.mpid,
+ cfmi->cfm.fault ? "fault" : "");
+
+ ds_put_format(&ds, "\tinterval: %dms\n", cfmi->ccm_interval_ms);
+ ds_put_format(&ds, "\tnext CCM tx: %lldms\n",
timer_msecs_until_expired(&cfmi->tx_timer));
- ds_put_format(ds, "\tnext fault check: %lldms\n",
+ ds_put_format(&ds, "\tnext fault check: %lldms\n",
timer_msecs_until_expired(&cfmi->fault_timer));
- ds_put_cstr(ds, "\n");
- HMAP_FOR_EACH (rmp, node, &cfm->remote_mps) {
- ds_put_format(ds, "Remote MPID %"PRIu16": %s\n", rmp->mpid,
+ ds_put_cstr(&ds, "\n");
+ HMAP_FOR_EACH (rmp, node, &cfmi->cfm.remote_mps) {
+ ds_put_format(&ds, "Remote MPID %"PRIu16": %s\n", rmp->mpid,
rmp->fault ? "fault" : "");
- ds_put_format(ds, "\trecv since check: %s",
+ ds_put_format(&ds, "\trecv since check: %s",
rmp->recv ? "true" : "false");
}
+
+ unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ ds_destroy(&ds);
}
-/*
- * Copyright (c) 2010 Nicira Networks.
+/* Copyright (c) 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct flow;
struct ofpbuf;
-struct ds;
/* Ethernet destination address of CCM packets. */
static const uint8_t eth_addr_ccm[6] OVS_UNUSED
uint16_t mpid; /* The MPID of this CFM. */
uint8_t maid[CCM_MAID_LEN]; /* The MAID of this CFM. */
int interval; /* The requested transmission interval. */
+ const char *name; /* Name of this CFM object. */
/* Statistics. */
struct hmap remote_mps; /* Expected remote MPs. */
bool fault; /* Indicates a connectivity fault. */
};
+void cfm_init(void);
+
struct cfm *cfm_create(void);
void cfm_destroy(struct cfm *);
void cfm_process_heartbeat(struct cfm *, const struct ofpbuf *packet);
-void cfm_dump_ds(const struct cfm *, struct ds *);
-
#endif /* cfm.h */
const char *name);
static bool port_is_bond_fake_iface(const struct port *);
-static unixctl_cb_func cfm_unixctl_show;
static unixctl_cb_func qos_unixctl_show;
static struct port *port_create(struct bridge *, const struct ovsrec_port *);
ovsdb_idl_omit(idl, &ovsrec_ssl_col_external_ids);
/* Register unixctl commands. */
- unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
unixctl_command_register("qos/show", qos_unixctl_show, NULL);
unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
NULL);
NULL);
lacp_init();
bond_init();
+ cfm_init();
}
void
}
}
\f
-/* CFM unixctl user interface functions. */
-static void
-cfm_unixctl_show(struct unixctl_conn *conn,
- const char *args, void *aux OVS_UNUSED)
-{
- struct ds ds = DS_EMPTY_INITIALIZER;
- struct iface *iface;
- const struct cfm *cfm;
-
- iface = iface_find(args);
- if (!iface) {
- unixctl_command_reply(conn, 501, "no such interface");
- return;
- }
-
- cfm = ofproto_port_get_cfm(iface->port->bridge->ofproto, iface->ofp_port);
-
- if (!cfm) {
- unixctl_command_reply(conn, 501, "CFM not enabled");
- return;
- }
-
- cfm_dump_ds(cfm, &ds);
- unixctl_command_reply(conn, 200, ds_cstr(&ds));
- ds_destroy(&ds);
-}
-\f
/* QoS unixctl user interface functions. */
struct qos_unixctl_show_cbdata {
cfm.mpid = mon->mpid;
cfm.interval = mon->interval ? *mon->interval : 1000;
+ cfm.name = iface->name;
memcpy(cfm.maid, maid, sizeof cfm.maid);