- Feature removals:
- Dropped support for "tun_id_from_cookie" OpenFlow extension.
(Use the extensible match extensions instead.)
+ - Removed the Maintenance_Point and Monitor tables in an effort
+ to simplify 802.1ag configuration.
v1.1.0 - 05 Apr 2011
------------------------
struct timer tx_timer; /* Send CCM when expired. */
struct timer fault_timer; /* Check for faults when expired. */
+
+ struct hmap remote_mps; /* Expected remote MPs. */
+};
+
+/* Remote MPs represent foreign network entities that are configured to have
+ * the same MAID as this CFM instance. */
+struct remote_mp {
+ uint16_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 fault; /* Indicates a connectivity fault. */
};
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
cfmi = xzalloc(sizeof *cfmi);
cfm = &cfmi->cfm;
- hmap_init(&cfm->remote_mps);
+ hmap_init(&cfmi->remote_mps);
cfm_generate_maid(cfmi);
list_push_back(&all_cfms, &cfmi->list_node);
return cfm;
return;
}
- HMAP_FOR_EACH_SAFE (rmp, rmp_next, node, &cfm->remote_mps) {
- hmap_remove(&cfm->remote_mps, &rmp->node);
+ HMAP_FOR_EACH_SAFE (rmp, rmp_next, node, &cfmi->remote_mps) {
+ hmap_remove(&cfmi->remote_mps, &rmp->node);
free(rmp);
}
- hmap_destroy(&cfm->remote_mps);
+ hmap_destroy(&cfmi->remote_mps);
list_remove(&cfmi->list_node);
free(cfmi);
}
struct remote_mp *rmp;
cfm->fault = false;
- HMAP_FOR_EACH (rmp, node, &cfm->remote_mps) {
+ HMAP_FOR_EACH (rmp, node, &cfmi->remote_mps) {
rmp->fault = !rmp->recv;
rmp->recv = false;
void
cfm_update_remote_mps(struct cfm *cfm, const uint16_t *mpids, size_t n_mpids)
{
+ struct cfm_internal *cfmi = cfm_to_internal(cfm);
size_t i;
struct hmap new_rmps;
struct remote_mp *rmp, *rmp_next;
continue;
}
- if ((rmp = lookup_remote_mp(&cfm->remote_mps, mpid))) {
- hmap_remove(&cfm->remote_mps, &rmp->node);
+ if ((rmp = lookup_remote_mp(&cfmi->remote_mps, mpid))) {
+ hmap_remove(&cfmi->remote_mps, &rmp->node);
} else {
rmp = xzalloc(sizeof *rmp);
rmp->mpid = mpid;
hmap_insert(&new_rmps, &rmp->node, hash_mpid(mpid));
}
- hmap_swap(&new_rmps, &cfm->remote_mps);
+ hmap_swap(&new_rmps, &cfmi->remote_mps);
HMAP_FOR_EACH_SAFE (rmp, rmp_next, node, &new_rmps) {
hmap_remove(&new_rmps, &rmp->node);
hmap_destroy(&new_rmps);
}
-/* Finds a 'remote_mp' with 'mpid' in 'cfm'. If no such 'remote_mp' exists
- * returns NULL. */
-const struct remote_mp *
-cfm_get_remote_mp(const struct cfm *cfm, uint16_t mpid)
-{
- return lookup_remote_mp(&cfm->remote_mps, mpid);
-}
-
/* Returns true if the CFM library should process packets from 'flow'. */
bool
cfm_should_process_flow(const struct flow *flow)
ccm_mpid = ntohs(ccm->mpid);
ccm_interval = ccm->flags & 0x7;
- rmp = lookup_remote_mp(&cfm->remote_mps, ccm_mpid);
+ rmp = lookup_remote_mp(&cfmi->remote_mps, ccm_mpid);
if (rmp) {
rmp->recv = true;
timer_msecs_until_expired(&cfmi->fault_timer));
ds_put_cstr(&ds, "\n");
- HMAP_FOR_EACH (rmp, node, &cfmi->cfm.remote_mps) {
+ HMAP_FOR_EACH (rmp, node, &cfmi->remote_mps) {
ds_put_format(&ds, "Remote MPID %"PRIu16": %s\n", rmp->mpid,
rmp->fault ? "fault" : "");
ds_put_format(&ds, "\trecv since check: %s",
const char *name; /* Name of this CFM object. */
/* Statistics. */
- struct hmap remote_mps; /* Expected remote MPs. */
bool fault; /* Indicates connectivity vaults. */
};
-/* Remote MPs represent foreign network entities that are configured to have
- * the same MAID as this CFM instance. */
-struct remote_mp {
- uint16_t mpid; /* The Maintenance Point ID of this 'remote_mp'. */
- struct hmap_node node; /* In 'cfm' 'remote_mps' or 'x_remote_mps'. */
-
- bool recv; /* CCM was received since last fault check. */
- bool fault; /* Indicates a connectivity fault. */
-};
-
void cfm_init(void);
struct cfm *cfm_create(void);
void cfm_update_remote_mps(struct cfm *, const uint16_t *mpid, size_t n_mpids);
-const struct remote_mp *cfm_get_remote_mp(const struct cfm *, uint16_t mpid);
-
bool cfm_should_process_flow(const struct flow *);
void cfm_process_heartbeat(struct cfm *, const struct ofpbuf *packet);
}
/* Configures connectivity fault management on 'ofp_port' in 'ofproto'. Takes
- * basic configuration from the configuration members in 'cfm', and the set of
- * remote maintenance points from the 'n_remote_mps' elements in 'remote_mps'.
- * Ignores the statistics members of 'cfm'.
+ * basic configuration from the configuration members in 'cfm', and the remote
+ * maintenance point ID from remote_mpid. Ignores the statistics members of
+ * 'cfm'.
*
* This function has no effect if 'ofproto' does not have a port 'ofp_port'. */
void
ofproto_port_set_cfm(struct ofproto *ofproto, uint16_t ofp_port,
- const struct cfm *cfm,
- const uint16_t *remote_mps, size_t n_remote_mps)
+ const struct cfm *cfm, uint16_t remote_mpid)
{
struct ofport *ofport;
int error;
return;
}
+ /* XXX: For configuration simplicity, we only support one remote_mpid
+ * outside of the CFM module. It's not clear if this is the correct long
+ * term solution or not. */
error = (ofproto->ofproto_class->set_cfm
- ? ofproto->ofproto_class->set_cfm(ofport, cfm,
- remote_mps, n_remote_mps)
+ ? ofproto->ofproto_class->set_cfm(ofport, cfm, &remote_mpid, 1)
: EOPNOTSUPP);
if (error) {
VLOG_WARN("%s: CFM configuration on port %"PRIu16" (%s) failed (%s)",
void ofproto_port_clear_cfm(struct ofproto *, uint16_t ofp_port);
void ofproto_port_set_cfm(struct ofproto *, uint16_t ofp_port,
- const struct cfm *,
- const uint16_t *remote_mps, size_t n_remote_mps);
+ const struct cfm *, uint16_t remote_mpid);
const struct cfm *ofproto_port_get_cfm(struct ofproto *, uint16_t ofp_port);
int ofproto_port_is_lacp_current(struct ofproto *, uint16_t ofp_port);
.IP "\fBQueue\fR"
Configuration for one queue within a \fBQoS\fR configuration. Records
may only be identified by UUID.
-.IP "\fBMonitor\fR"
-Connectivity Monitoring attached to an \fBInterface\fR. Records may be
-identified by \fBInterface\fR name.
-.IP "\fBMaintenance_Point\fR"
-Maintenance Point managed by a \fBMonitor\fR.
.IP "\fBMirror\fR"
A port mirroring configuration attached to a bridge. Records may be
identified by mirror name.
\fIuuid2\fR" to destroy each of them.)
.SS "Connectivity Monitoring"
.PP
-Create a Monitor which manages a couple of remote Maintenance Points on eth0.
+Monitor connectivity to a remote maintenance point on eth0.
.IP
-.B "ovs\-vsctl \-\- set Interface eth0 Monitor=@newmon \(rs"
-.IP
-.B "\-\- \-\-id=@newmon create Monitor mpid=1 remote_mps=@mp2,@mp3 \(rs"
-.IP
-.B "\-\- \-\-id=@mp2 create Maintenance_Point mpid=2 \(rs"
-.IP
-.B "\-\- \-\-id=@mp3 create Maintenance_Point mpid=3"
+.B "ovs\-vsctl set Interface eth0 cfm_mpid=1 cfm_remote_mpid=2"
.PP
-Deconfigure the Monitor record from above:
+Deconfigure connectivity monitoring from above:
.IP
-.B "ovs\-vsctl clear Interface eth0 Monitor"
+.B "ovs\-vsctl clear Interface eth0 cfm_mpid cfm_remote_mpid"
.SS "NetFlow"
.PP
Configure bridge \fBbr0\fR to send NetFlow records to UDP port 5566 on
{{&ovsrec_table_port, &ovsrec_port_col_name, &ovsrec_port_col_qos},
{NULL, NULL, NULL}}},
- {&ovsrec_table_monitor,
- {{&ovsrec_table_interface,
- &ovsrec_interface_col_name,
- &ovsrec_interface_col_monitor},
- {NULL, NULL, NULL}}},
-
- {&ovsrec_table_maintenance_point,
- {{NULL, NULL, NULL},
- {NULL, NULL, NULL}}},
-
{&ovsrec_table_queue,
{{NULL, NULL, NULL},
{NULL, NULL, NULL}}},
ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_status);
ovsdb_idl_omit(idl, &ovsrec_controller_col_external_ids);
- ovsdb_idl_omit_alert(idl, &ovsrec_maintenance_point_col_fault);
-
- ovsdb_idl_omit_alert(idl, &ovsrec_monitor_col_fault);
-
ovsdb_idl_omit(idl, &ovsrec_qos_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_queue_col_external_ids);
static bool
iface_refresh_cfm_stats(struct iface *iface)
{
- const struct ovsrec_monitor *mon;
+ const struct ovsrec_interface *cfg = iface->cfg;
const struct cfm *cfm;
bool changed = false;
- size_t i;
- mon = iface->cfg->monitor;
cfm = ofproto_port_get_cfm(iface->port->bridge->ofproto, iface->ofp_port);
- if (!cfm || !mon) {
+ if (!cfm) {
return false;
}
- for (i = 0; i < mon->n_remote_mps; i++) {
- const struct ovsrec_maintenance_point *mp;
- const struct remote_mp *rmp;
-
- mp = mon->remote_mps[i];
- rmp = cfm_get_remote_mp(cfm, mp->mpid);
-
- if (mp->n_fault != 1 || mp->fault[0] != rmp->fault) {
- ovsrec_maintenance_point_set_fault(mp, &rmp->fault, 1);
- changed = true;
- }
- }
-
- if (mon->n_fault != 1 || mon->fault[0] != cfm->fault) {
- ovsrec_monitor_set_fault(mon, &cfm->fault, 1);
+ if (cfg->n_cfm_fault != 1 || cfg->cfm_fault[0] != cfm->fault) {
+ ovsrec_interface_set_cfm_fault(cfg, &cfm->fault, 1);
changed = true;
}
static void
iface_configure_cfm(struct iface *iface)
{
- size_t i;
+ const struct ovsrec_interface *cfg = iface->cfg;
struct cfm cfm;
- uint16_t *remote_mps;
- struct ovsrec_monitor *mon;
-
- mon = iface->cfg->monitor;
- if (!mon) {
+ if (!cfg->n_cfm_mpid || !cfg->n_cfm_remote_mpid) {
ofproto_port_clear_cfm(iface->port->bridge->ofproto, iface->ofp_port);
return;
}
- cfm.mpid = mon->mpid;
- cfm.interval = mon->interval ? *mon->interval : 1000;
+ cfm.mpid = *cfg->cfm_mpid;
cfm.name = iface->name;
+ cfm.interval = atoi(get_interface_other_config(iface->cfg,
+ "cfm_interval", "0"));
- remote_mps = xzalloc(mon->n_remote_mps * sizeof *remote_mps);
- for(i = 0; i < mon->n_remote_mps; i++) {
- remote_mps[i] = mon->remote_mps[i]->mpid;
+ if (cfm.interval <= 0) {
+ cfm.interval = 1000;
}
ofproto_port_set_cfm(iface->port->bridge->ofproto, iface->ofp_port,
- &cfm, remote_mps, mon->n_remote_mps);
- free(remote_mps);
+ &cfm, *cfg->cfm_remote_mpid);
}
/* Read carrier or miimon status directly from 'iface''s netdev, according to
Bridge -> NetFlow [label="netflow"];
QoS [style=bold];
QoS -> Queue [label="queues value"];
- Monitor [];
- Monitor -> Maintenance_Point [label="remote_mps"];
sFlow [];
Open_vSwitch [style=bold];
Open_vSwitch -> Bridge [label="bridges"];
Mirror -> Port [style=dotted, constraint=false, label="output_port"];
Mirror -> Port [style=dotted, constraint=false, label="select_dst_port"];
Interface [];
- Interface -> Monitor [label="monitor"];
NetFlow [];
- Maintenance_Point [];
Port [];
Port -> QoS [label="qos"];
Port -> Interface [label="interfaces"];
{"name": "Open_vSwitch",
- "version": "3.5.0",
- "cksum": "1684955806 14964",
+ "version": "4.0.0",
+ "cksum": "2606080158 14328",
"tables": {
"Open_vSwitch": {
"columns": {
"ofport": {
"type": {"key": "integer", "min": 0, "max": 1},
"ephemeral": true},
- "monitor": {
+ "cfm_mpid": {
"type": {
- "key": {"type": "uuid", "refTable": "Monitor"},
+ "key": {"type": "integer", "minInteger": 1, "maxInteger": 8191},
+ "min": 0,
+ "max": 1}},
+ "cfm_remote_mpid": {
+ "type" : {
+ "key": { "type": "integer", "minInteger": 1, "maxInteger": 8191},
+ "min": 0,
+ "max": 1}},
+ "cfm_fault": {
+ "type": {
+ "key": { "type": "boolean"},
"min": 0,
"max": 1}},
"lacp_current": {
"mtu": {
"type": {"key": "integer", "min": 0, "max": 1},
"ephemeral": true}}},
- "Monitor": {
- "columns": {
- "mpid": {
- "type" : {
- "key": { "type": "integer", "minInteger": 1, "maxInteger": 8191}}},
- "interval": {
- "type": {
- "key": { "type": "integer", "minInteger": 100},
- "min": 0,
- "max": 1}},
- "remote_mps": {
- "type": {
- "key": { "type": "uuid", "refTable": "Maintenance_Point"},
- "min": 0,
- "max": "unlimited"}},
- "fault": {
- "type": {
- "key": { "type": "boolean"},
- "min": 0,
- "max": 1},
- "ephemeral": true}}},
- "Maintenance_Point": {
- "columns": {
- "mpid": {
- "type" : {
- "key": { "type": "integer", "minInteger": 1, "maxInteger": 8191}},
- "mutable": false},
- "fault": {
- "type": {
- "key": { "type": "boolean"},
- "min": 0,
- "max": 1},
- "ephemeral": true}}},
"QoS": {
"columns": {
"type": {
</column>
</group>
- <group title="Other Features">
+ <group title="Connectivity Fault Management">
+ <p>
+ 802.1ag Connectivity Fault Management (CFM) allows a group of
+ Maintenance Points (MPs) called a Maintenance Association (MA) to
+ detect connectivity problems with each other. MPs within a MA should
+ have complete and exclusive interconnectivity. This is verified by
+ occasionally broadcasting Continuity Check Messages (CCMs) at a
+ configurable transmission interval.
+ </p>
+
+ <column name="cfm_mpid">
+ A Maintenance Point ID (MPID) uniquely identifies each endpoint within
+ a Maintenance Association. The MPID is used to identify this endpoint
+ to other Maintenance Points in the MA. Each end of a link being
+ monitored should have a different MPID. Must be configured to enable
+ CFM on this <ref table="Interface"/>.
+ </column>
- <column name="monitor">
- Connectivity monitor configuration for this interface.
+ <column name="cfm_remote_mpid">
+ The MPID of the remote endpoint being monitored. If this
+ <ref table="Interface"/> does not have connectivity to an endpoint
+ advertising the configured MPID, a fault is signalled. Must be
+ configured to enable CFM on this <ref table="Interface"/>
</column>
+ <column name="cfm_fault">
+ Indicates a connectivity fault triggered by an inability to receive
+ heartbeats from the remote endpoint.
+ </column>
+ </group>
+
+ <group title="Other Features">
+
<column name="lacp_current">
Boolean value indicating LACP status for this interface. If true, this
interface has current LACP information about its LACP partner. This
<column name="other_config">
Key-value pairs for rarely used interface features.
<dl>
+ <dt><code>cfm_interval</code></dt>
+ <dd> The transmission interval of CFM heartbeats in milliseconds.
+ Three missed heartbeat receptions indicate a connectivity fault.
+ Defaults to 1000ms. </dd>
<dt><code>bond-stable-id</code></dt>
<dd> A positive integer using in <code>stable</code> bond mode to
make slave selection decisions. Allocating
</column>
</table>
- <table name="Monitor" title="Connectivity Monitor configuration">
- <p>
- A <ref table="Monitor"/> attaches to an <ref table="Interface"/> to
- implement 802.1ag Connectivity Fault Management (CFM). CFM allows a
- group of Maintenance Points (MPs) called a Maintenance Association (MA)
- to detect connectivity problems with each other. MPs within a MA should
- have complete and exclusive interconnectivity. This is verified by
- occasionally broadcasting Continuity Check Messages (CCMs) at a
- configurable transmission interval. A <ref table="Monitor"/> is
- responsible for collecting data about other MPs in its MA and
- broadcasting CCMs.
- </p>
-
- <group title="Monitor Configuration">
- <column name="mpid">
- A Maintenance Point ID (MPID) uniquely identifies each endpoint within
- a Maintenance Association. The MPID is used to identify this
- <ref table="Monitor"/> to other endpoints in the MA.
- </column>
-
- <column name="remote_mps">
- A set of <ref table="Maintenance_Points"/> which this
- <ref table="Monitor"/> should have connectivity to. If this
- <ref table="Monitor"/> does not have connectivity to any MPs in this
- set, or has connectivity to any MPs not in this set, a fault is
- signaled.
- </column>
-
- <column name="interval">
- The transmission interval of CCMs in milliseconds. Three missed CCMs
- indicate a connectivity fault. Defaults to 1000ms.
- </column>
- </group>
-
- <group title="Monitor Status">
- <column name="fault">
- Indicates a Connectivity Fault caused by a configuration error, a down
- remote MP, or unexpected connectivity to a remote MAID or remote MP.
- </column>
- </group>
- </table>
-
- <table name="Maintenance_Point" title="Maintenance Point configuration">
- <p>
- A <ref table="Maintenance_Point"/> represents a MP which a
- <ref table="Monitor"/> has or should have connectivity to.
- </p>
-
- <group title="Maintenance_Point Configuration">
- <column name="mpid">
- A Maintenance Point ID (MPID) uniquely identifies each endpoint within
- a Maintenance Association. All MPs within a MA should have a unique
- MPID.
- </column>
- </group>
-
- <group title="Maintenance_Point Status">
- <column name="fault">
- Indicates a connectivity fault.
- </column>
- </group>
- </table>
-
<table name="Mirror" title="Port mirroring (SPAN/RSPAN).">
<p>A port mirror within a <ref table="Bridge"/>.</p>
<p>A port mirror configures a bridge to send selected frames to special