From: Ethan Jackson Date: Fri, 7 Oct 2011 05:43:05 +0000 (-0700) Subject: cfm: New 'cfm_opstate' setting. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=86dc65011b820698dab5f1e4cb5083d20f14aad4;p=openvswitch cfm: New 'cfm_opstate' setting. In some cases, a controller may want to take an interface down for forwarding purposes, but avoid completely deconfiguring CFM and thus lose all connectivity monitoring. The new 'cfm_opstate' setting is a way to achieve this behavior. --- diff --git a/lib/cfm.c b/lib/cfm.c index e6fea3a6..0d79beed 100644 --- a/lib/cfm.c +++ b/lib/cfm.c @@ -71,7 +71,8 @@ struct ccm { /* Defined by ITU-T Y.1731 should be zero */ ovs_be16 interval_ms_x; /* Transmission interval in ms. */ ovs_be64 mpid64; /* MPID in extended mode. */ - uint8_t zero[6]; + uint8_t opdown; /* Operationally down. */ + uint8_t zero[5]; /* TLV space. */ uint8_t end_tlv; @@ -86,6 +87,8 @@ struct cfm { bool extended; /* Extended mode. */ bool fault; /* Indicates connectivity fault. */ bool unexpected_recv; /* Received an unexpected CCM. */ + bool opup; /* Operational State. */ + bool remote_opup; /* Remote Operational State. */ uint32_t seq; /* The sequence number of our last CCM. */ uint8_t ccm_interval; /* The CCM transmission interval. */ @@ -112,6 +115,7 @@ struct remote_mp { bool recv; /* CCM was received since last fault check. */ bool rdi; /* Remote Defect Indicator. Indicates remote_mp isn't receiving CCMs that it's expecting to. */ + bool opup; /* Operational State. */ }; static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); @@ -244,6 +248,7 @@ cfm_create(const char *name) hmap_init(&cfm->remote_mps); cfm_generate_maid(cfm); hmap_insert(&all_cfms, &cfm->hmap_node, hash_string(cfm->name, 0)); + cfm->remote_opup = true; return cfm; } @@ -284,6 +289,7 @@ cfm_run(struct cfm *cfm) cfm->rmps_array = xmalloc(hmap_count(&cfm->remote_mps) * sizeof *cfm->rmps_array); + cfm->remote_opup = true; HMAP_FOR_EACH_SAFE (rmp, rmp_next, node, &cfm->remote_mps) { if (!rmp->recv) { @@ -306,6 +312,10 @@ cfm_run(struct cfm *cfm) cfm->fault = true; } + if (!rmp->opup) { + cfm->remote_opup = rmp->opup; + } + cfm->rmps_array[cfm->rmps_array_len++] = rmp->mpid; } } @@ -349,9 +359,11 @@ cfm_compose_ccm(struct cfm *cfm, struct ofpbuf *packet, if (cfm->extended) { ccm->mpid = htons(hash_mpid(cfm->mpid)); ccm->mpid64 = htonll(cfm->mpid); + ccm->opdown = !cfm->opup; } else { ccm->mpid = htons(cfm->mpid); ccm->mpid64 = htonll(0); + ccm->opdown = 0; } if (cfm->ccm_interval == 0) { @@ -384,6 +396,7 @@ cfm_configure(struct cfm *cfm, const struct cfm_settings *s) cfm->mpid = s->mpid; cfm->extended = s->extended; + cfm->opup = s->opup; interval = ms_to_ccm_interval(s->interval); interval_ms = ccm_interval_to_ms(interval); @@ -455,8 +468,15 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) struct remote_mp *rmp; uint64_t ccm_mpid; + bool ccm_opdown; - ccm_mpid = cfm->extended ? ntohll(ccm->mpid64) : ntohs(ccm->mpid); + if (cfm->extended) { + ccm_mpid = ntohll(ccm->mpid64); + ccm_opdown = ccm->opdown; + } else { + ccm_mpid = ntohs(ccm->mpid); + ccm_opdown = false; + } if (ccm_interval != cfm->ccm_interval) { VLOG_WARN_RL(&rl, "%s: received a CCM with an invalid interval" @@ -472,20 +492,24 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) } rmp = lookup_remote_mp(cfm, ccm_mpid); + if (!rmp) { + if (hmap_count(&cfm->remote_mps) < CFM_MAX_RMPS) { + rmp = xmalloc(sizeof *rmp); + hmap_insert(&cfm->remote_mps, &rmp->node, hash_mpid(ccm_mpid)); + } else { + cfm->unexpected_recv = true; + VLOG_WARN_RL(&rl, + "%s: dropped CCM with MPID %"PRIu64" from MAC " + ETH_ADDR_FMT, cfm->name, ccm_mpid, + ETH_ADDR_ARGS(eth->eth_src)); + } + } + if (rmp) { - rmp->recv = true; - rmp->rdi = ccm_rdi; - } else if (hmap_count(&cfm->remote_mps) < CFM_MAX_RMPS) { - rmp = xmalloc(sizeof *rmp); rmp->mpid = ccm_mpid; rmp->recv = true; rmp->rdi = ccm_rdi; - hmap_insert(&cfm->remote_mps, &rmp->node, hash_mpid(rmp->mpid)); - } else { - cfm->unexpected_recv = true; - VLOG_WARN_RL(&rl, "%s: dropped CCM with MPID %"PRIu64" from MAC " - ETH_ADDR_FMT, cfm->name, ccm_mpid, - ETH_ADDR_ARGS(eth->eth_src)); + rmp->opup = !ccm_opdown; } VLOG_DBG("%s: received CCM (seq %"PRIu32") (mpid %"PRIu64")" @@ -502,6 +526,16 @@ cfm_get_fault(const struct cfm *cfm) return cfm->fault; } +/* Gets the operational state of 'cfm'. 'cfm' is considered operationally down + * if it has received a CCM with the operationally down bit set from any of its + * remote maintenance points. Returns true if 'cfm' is operationally up. False + * otherwise. */ +bool +cfm_get_opup(const struct cfm *cfm) +{ + return cfm->remote_opup; +} + /* Populates 'rmps' with an array of remote maintenance points reachable by * 'cfm'. The number of remote maintenance points is written to 'n_rmps'. * 'cfm' retains ownership of the array written to 'rmps' */ @@ -537,6 +571,9 @@ cfm_print_details(struct ds *ds, const struct cfm *cfm) cfm->fault ? " fault" : "", cfm->unexpected_recv ? " unexpected_recv" : ""); + ds_put_format(ds, "\topstate: %s\n", cfm->opup ? "up" : "down"); + ds_put_format(ds, "\tremote_opstate: %s\n", + cfm->remote_opup ? "up" : "down"); ds_put_format(ds, "\tinterval: %dms\n", cfm->ccm_interval_ms); ds_put_format(ds, "\tnext CCM tx: %lldms\n", timer_msecs_until_expired(&cfm->tx_timer)); @@ -549,6 +586,7 @@ cfm_print_details(struct ds *ds, const struct cfm *cfm) rmp->rdi ? " rdi" : ""); ds_put_format(ds, "\trecv since check: %s\n", rmp->recv ? "true" : "false"); + ds_put_format(ds, "\topstate: %s\n", rmp->opup? "up" : "down"); } } diff --git a/lib/cfm.h b/lib/cfm.h index a031ab22..1c46ffa8 100644 --- a/lib/cfm.h +++ b/lib/cfm.h @@ -28,6 +28,7 @@ struct cfm_settings { uint64_t mpid; /* The MPID of this CFM. */ int interval; /* The requested transmission interval. */ bool extended; /* Run in extended mode. */ + bool opup; /* Operational State. */ }; void cfm_init(void); @@ -41,6 +42,7 @@ bool cfm_configure(struct cfm *, const struct cfm_settings *); bool cfm_should_process_flow(const struct cfm *cfm, const struct flow *); void cfm_process_heartbeat(struct cfm *, const struct ofpbuf *packet); bool cfm_get_fault(const struct cfm *); +bool cfm_get_opup(const struct cfm *); void cfm_get_remote_mpids(const struct cfm *, const uint64_t **rmps, size_t *n_rmps); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 9e8b1fb5..1ffe36a9 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1568,7 +1568,8 @@ port_run(struct ofport_dpif *ofport) ofpbuf_uninit(&packet); } - enable = enable && !cfm_get_fault(ofport->cfm); + enable = enable && !cfm_get_fault(ofport->cfm) + && cfm_get_opup(ofport->cfm); } if (ofport->bundle) { diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index de3ffba8..186f2501 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -2668,7 +2668,7 @@ static void iface_configure_cfm(struct iface *iface) { const struct ovsrec_interface *cfg = iface->cfg; - const char *extended_str; + const char *extended_str, *opstate_str; struct cfm_settings s; if (!cfg->n_cfm_mpid) { @@ -2687,6 +2687,9 @@ iface_configure_cfm(struct iface *iface) "false"); s.extended = !strcasecmp("true", extended_str); + opstate_str = get_interface_other_config(iface->cfg, "cfm_opstate", "up"); + s.opup = !strcasecmp("up", opstate_str); + ofproto_port_set_cfm(iface->port->bridge->ofproto, iface->ofp_port, &s); } diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index b85d26cd..560d2224 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -1447,6 +1447,16 @@ compatibility with 802.1ag compliant implementations. Defaults to false. + + When down, the CFM module marks all CCMs it generates as + operationally down without triggering a fault. This allows remote + maintenance points to choose not to forward traffic to the + on which this CFM module is running. + Currently, in Open vSwitch, the opdown bit of CCMs affects + s participating in bonds, and the bundle + OpenFlow action. This setting is ignored when CFM is not in extended + mode. Defaults to up. +