X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fcfm.c;h=d373f4229a5dfafe531048d3a32bd4583538e212;hb=541bc79f73add327072470c9bc3febb4195cdb3c;hp=1e05853d70ef0174f53a52d08d02ea80c26c9b69;hpb=8210113e95b679acc5e08ac81c1b8580b7912ab6;p=openvswitch diff --git a/lib/cfm.c b/lib/cfm.c index 1e05853d..d373f422 100644 --- a/lib/cfm.c +++ b/lib/cfm.c @@ -85,15 +85,19 @@ struct cfm { uint64_t mpid; bool extended; /* Extended mode. */ - bool fault; /* Indicates connectivity fault. */ - bool unexpected_recv; /* Received an unexpected CCM. */ + int fault; /* Connectivity fault status. */ + int recv_fault; /* Bit mask of faults occuring on receive. */ bool opup; /* Operational State. */ bool remote_opup; /* Remote Operational State. */ + int fault_override; /* Manual override of 'fault' status. + Ignored if negative. */ + 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. */ uint16_t ccm_vlan; /* Vlan tag of CCM PDUs. */ + uint8_t ccm_pcp; /* Priority of CCM PDUs. */ uint8_t maid[CCM_MAID_LEN]; /* The MAID of this CFM. */ struct timer tx_timer; /* Send CCM when expired. */ @@ -124,6 +128,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 30); static struct hmap all_cfms = HMAP_INITIALIZER(&all_cfms); static unixctl_cb_func cfm_unixctl_show; +static unixctl_cb_func cfm_unixctl_set_fault; static const uint8_t * cfm_ccm_addr(const struct cfm *cfm) @@ -131,6 +136,36 @@ cfm_ccm_addr(const struct cfm *cfm) return cfm->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 ""; + } +} + +static void +ds_put_cfm_fault(struct ds *ds, int fault) +{ + size_t length = ds->length; + 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)); + } + } + + if (ds->length > length) { + ds_truncate(ds, ds->length - 1); + } +} + static void cfm_generate_maid(struct cfm *cfm) { @@ -235,6 +270,8 @@ cfm_init(void) { unixctl_command_register("cfm/show", "[interface]", 0, 1, cfm_unixctl_show, NULL); + unixctl_command_register("cfm/set-fault", "[interface] normal|false|true", + 1, 2, cfm_unixctl_set_fault, NULL); } /* Allocates a 'cfm' object called 'name'. 'cfm' should be initialized by @@ -250,6 +287,7 @@ cfm_create(const char *name) cfm_generate_maid(cfm); hmap_insert(&all_cfms, &cfm->hmap_node, hash_string(cfm->name, 0)); cfm->remote_opup = true; + cfm->fault_override = -1; return cfm; } @@ -283,8 +321,8 @@ cfm_run(struct cfm *cfm) struct remote_mp *rmp, *rmp_next; bool old_cfm_fault = cfm->fault; - cfm->fault = cfm->unexpected_recv; - cfm->unexpected_recv = false; + cfm->fault = cfm->recv_fault; + cfm->recv_fault = 0; cfm->rmps_array_len = 0; free(cfm->rmps_array); @@ -305,13 +343,13 @@ cfm_run(struct cfm *cfm) if (rmp->mpid == cfm->mpid) { VLOG_WARN_RL(&rl,"%s: received CCM with local MPID" " %"PRIu64, cfm->name, rmp->mpid); - cfm->fault = true; + cfm->fault |= CFM_FAULT_LOOPBACK; } if (rmp->rdi) { VLOG_DBG("%s: RDI bit flagged from RMP %"PRIu64, cfm->name, rmp->mpid); - cfm->fault = true; + cfm->fault |= CFM_FAULT_RDI; } if (!rmp->opup) { @@ -323,12 +361,16 @@ cfm_run(struct cfm *cfm) } if (hmap_is_empty(&cfm->remote_mps)) { - cfm->fault = true; + cfm->fault |= CFM_FAULT_RECV; } if (old_cfm_fault != cfm->fault) { - VLOG_INFO_RL(&rl, "%s: CFM fault status changed to %s", - cfm->name, cfm->fault ? "true" : "false"); + struct ds ds = DS_EMPTY_INITIALIZER; + + ds_put_cfm_fault(&ds, cfm->fault); + VLOG_INFO_RL(&rl, "%s: CFM fault status changed: %s", cfm->name, + ds_cstr_ro(&ds)); + ds_destroy(&ds); } timer_set_duration(&cfm->fault_timer, interval); @@ -354,8 +396,9 @@ cfm_compose_ccm(struct cfm *cfm, struct ofpbuf *packet, timer_set_duration(&cfm->tx_timer, cfm->ccm_interval_ms); eth_compose(packet, cfm_ccm_addr(cfm), eth_src, ETH_TYPE_CFM, sizeof *ccm); - if (cfm->ccm_vlan) { - eth_push_vlan(packet, htons(cfm->ccm_vlan)); + if (cfm->ccm_vlan || cfm->ccm_pcp) { + uint16_t tci = cfm->ccm_vlan | (cfm->ccm_pcp << VLAN_PCP_SHIFT); + eth_push_vlan(packet, htons(tci)); } ccm = packet->l3; @@ -413,6 +456,7 @@ cfm_configure(struct cfm *cfm, const struct cfm_settings *s) interval_ms = ccm_interval_to_ms(interval); cfm->ccm_vlan = s->ccm_vlan & VLAN_VID_MASK; + cfm->ccm_pcp = s->ccm_pcp & (VLAN_PCP_MASK >> VLAN_PCP_SHIFT); if (cfm->extended && interval_ms != s->interval) { interval = 0; interval_ms = MIN(s->interval, UINT16_MAX); @@ -471,7 +515,7 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) * bonds. Furthermore, faults can be maliciously triggered by crafting * invalid CCMs. */ if (memcmp(ccm->maid, cfm->maid, sizeof ccm->maid)) { - cfm->unexpected_recv = true; + cfm->recv_fault |= CFM_FAULT_MAID; VLOG_WARN_RL(&rl, "%s: Received unexpected remote MAID from MAC " ETH_ADDR_FMT, cfm->name, ETH_ADDR_ARGS(eth->eth_src)); } else { @@ -512,7 +556,7 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) rmp = xzalloc(sizeof *rmp); hmap_insert(&cfm->remote_mps, &rmp->node, hash_mpid(ccm_mpid)); } else { - cfm->unexpected_recv = true; + cfm->recv_fault |= CFM_FAULT_OVERFLOW; VLOG_WARN_RL(&rl, "%s: dropped CCM with MPID %"PRIu64" from MAC " ETH_ADDR_FMT, cfm->name, ccm_mpid, @@ -541,11 +585,15 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p) } } -/* Gets the fault status of 'cfm'. Returns true when 'cfm' has detected - * connectivity problems, false otherwise. */ -bool +/* Gets the fault status of 'cfm'. Returns a bit mask of 'cfm_fault_reason's + * indicating the cause of the connectivity fault, or zero if there is no + * fault. */ +int cfm_get_fault(const struct cfm *cfm) { + if (cfm->fault_override >= 0) { + return cfm->fault_override ? CFM_FAULT_OVERRIDE : 0; + } return cfm->fault; } @@ -589,10 +637,16 @@ cfm_print_details(struct ds *ds, const struct cfm *cfm) struct remote_mp *rmp; ds_put_format(ds, "---- %s ----\n", cfm->name); - ds_put_format(ds, "MPID %"PRIu64":%s%s%s\n", cfm->mpid, + ds_put_format(ds, "MPID %"PRIu64":%s%s\n", cfm->mpid, cfm->extended ? " extended" : "", - cfm->fault ? " fault" : "", - cfm->unexpected_recv ? " unexpected_recv" : ""); + cfm->fault_override >= 0 ? " fault_override" : ""); + + + if (cfm_get_fault(cfm)) { + ds_put_cstr(ds, "\tfault: "); + ds_put_cfm_fault(ds, cfm_get_fault(cfm)); + ds_put_cstr(ds, "\n"); + } ds_put_format(ds, "\topstate: %s\n", cfm->opup ? "up" : "down"); ds_put_format(ds, "\tremote_opstate: %s\n", @@ -636,3 +690,38 @@ cfm_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], unixctl_command_reply(conn, 200, ds_cstr(&ds)); ds_destroy(&ds); } + +static void +cfm_unixctl_set_fault(struct unixctl_conn *conn, int argc, const char *argv[], + void *aux OVS_UNUSED) +{ + const char *fault_str = argv[argc - 1]; + int fault_override; + struct cfm *cfm; + + if (!strcasecmp("true", fault_str)) { + fault_override = 1; + } else if (!strcasecmp("false", fault_str)) { + fault_override = 0; + } else if (!strcasecmp("normal", fault_str)) { + fault_override = -1; + } else { + unixctl_command_reply(conn, 501, "unknown fault string"); + return; + } + + if (argc > 2) { + cfm = cfm_find(argv[1]); + if (!cfm) { + unixctl_command_reply(conn, 501, "no such CFM object"); + return; + } + cfm->fault_override = fault_override; + } else { + HMAP_FOR_EACH (cfm, hmap_node, &all_cfms) { + cfm->fault_override = fault_override; + } + } + + unixctl_command_reply(conn, 200, "OK"); +}