From: dv1tas Date: Wed, 19 Jun 2013 07:49:36 +0000 (+0000) Subject: Bridge Assurance functionality. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0709c951985b3bcc4b6a1983294d5214892bc8f4;p=people%2Fms%2Fmstpd.git Bridge Assurance functionality. 1. Port type network ("setportnetwork" command) needs to be configured on ports on which bridge assurance functionality needs to be enforced. The functionality is enforced only for Operation Point-to-Point links and only when the operational version is RSTP/MSTP. 2. BPDU's are sent only on designated ports normally. For a network port type, BPDU's will be sent always and the port expects to receive BPDU's every hello time interval. 3. When a network port does not receive BPDU's in 3*hello_timer seconds from peer, the port is put in discarding state (with Bridge assurance inconsistency error in syslog), but BPDU's need to be sent out from the port every hello interval, though. 4. When an inconsistent bridge assurance port receives a BPDU later, the inconsistency is cleared and the port is transitioned to learning/forwarding as usual now. 5. Added hidden command "setdonttxmt" to not transmit BPDU's on demand, to test the functionality. Signed-off-by: Satish Ashok Signed-off-by: Vitalii Demianets git-svn-id: svn://svn.code.sf.net/p/mstpd/code/trunk@46 fbe50366-0c72-4402-a84b-5d246361dba7 --- diff --git a/ctl_main.c b/ctl_main.c index 6aa79be..67465c5 100644 --- a/ctl_main.c +++ b/ctl_main.c @@ -134,6 +134,8 @@ typedef enum { PARAM_DISPUTED, PARAM_BPDUGUARDPORT, PARAM_BPDUGUARDERROR, + PARAM_NETWORKPORT, + PARAM_BA_INCONSISTENT, } param_id_t; typedef struct { @@ -457,32 +459,34 @@ static int cmd_showtree(int argc, char *const *argv) }) static const cmd_param_t cist_port_params[] = { - { PARAM_ENABLED, "enabled" }, - { PARAM_ROLE, "role" }, - { PARAM_STATE, "state" }, - { PARAM_PORTID, "port-id" }, - { PARAM_EXTPORTCOST, "external-port-cost" }, - { PARAM_ADMINEXTCOST, "admin-external-cost" }, - { PARAM_INTPORTCOST, "internal-port-cost" }, - { PARAM_ADMININTCOST, "admin-internal-cost" }, - { PARAM_DSGNROOT, "designated-root" }, - { PARAM_DSGNEXTCOST, "dsgn-external-cost" }, - { PARAM_DSGNRROOT, "dsgn-regional-root" }, - { PARAM_DSGNINTCOST, "dsgn-internal-cost" }, - { PARAM_DSGNBR, "designated-bridge" }, - { PARAM_DSGNPORT, "designated-port" }, - { PARAM_ADMINEDGEPORT, "admin-edge-port" }, - { PARAM_AUTOEDGEPORT, "auto-edge-port" }, - { PARAM_OPEREDGEPORT, "oper-edge-port" }, - { PARAM_TOPCHNGACK, "topology-change-ack" }, - { PARAM_P2P, "point-to-point" }, - { PARAM_ADMINP2P, "admin-point-to-point" }, - { PARAM_RESTRROLE, "restricted-role" }, - { PARAM_RESTRTCN, "restricted-TCN" }, - { PARAM_PORTHELLOTIME, "port-hello-time" }, - { PARAM_DISPUTED, "disputed" }, - { PARAM_BPDUGUARDPORT, "bpdu-guard-port" }, - { PARAM_BPDUGUARDERROR,"bpdu-guard-error" }, + { PARAM_ENABLED, "enabled" }, + { PARAM_ROLE, "role" }, + { PARAM_STATE, "state" }, + { PARAM_PORTID, "port-id" }, + { PARAM_EXTPORTCOST, "external-port-cost" }, + { PARAM_ADMINEXTCOST, "admin-external-cost" }, + { PARAM_INTPORTCOST, "internal-port-cost" }, + { PARAM_ADMININTCOST, "admin-internal-cost" }, + { PARAM_DSGNROOT, "designated-root" }, + { PARAM_DSGNEXTCOST, "dsgn-external-cost" }, + { PARAM_DSGNRROOT, "dsgn-regional-root" }, + { PARAM_DSGNINTCOST, "dsgn-internal-cost" }, + { PARAM_DSGNBR, "designated-bridge" }, + { PARAM_DSGNPORT, "designated-port" }, + { PARAM_ADMINEDGEPORT, "admin-edge-port" }, + { PARAM_AUTOEDGEPORT, "auto-edge-port" }, + { PARAM_OPEREDGEPORT, "oper-edge-port" }, + { PARAM_TOPCHNGACK, "topology-change-ack" }, + { PARAM_P2P, "point-to-point" }, + { PARAM_ADMINP2P, "admin-point-to-point" }, + { PARAM_RESTRROLE, "restricted-role" }, + { PARAM_RESTRTCN, "restricted-TCN" }, + { PARAM_PORTHELLOTIME, "port-hello-time" }, + { PARAM_DISPUTED, "disputed" }, + { PARAM_BPDUGUARDPORT, "bpdu-guard-port" }, + { PARAM_BPDUGUARDERROR, "bpdu-guard-error" }, + { PARAM_NETWORKPORT, "network-port" }, + { PARAM_BA_INCONSISTENT,"ba-inconsistent" }, }; static int detail = 0; @@ -554,6 +558,10 @@ static int do_showport(int br_index, const char *bridge_name, BOOL_STR(s.bpdu_guard_port)); printf("bpdu guard error %s\n", BOOL_STR(s.bpdu_guard_error)); + printf(" network port %-23s ", + BOOL_STR(s.network_port)); + printf("BA inconsistent %s\n", + BOOL_STR(s.ba_inconsistent)); } else { @@ -648,6 +656,12 @@ static int do_showport(int br_index, const char *bridge_name, case PARAM_BPDUGUARDERROR: printf("%s\n", BOOL_STR(s.bpdu_guard_error)); break; + case PARAM_NETWORKPORT: + printf("%s\n", BOOL_STR(s.network_port)); + break; + case PARAM_BA_INCONSISTENT: + printf("%s\n", BOOL_STR(s.ba_inconsistent)); + break; default: return -2; /* -2 = unknown param */ } @@ -1103,6 +1117,28 @@ static int cmd_setportbpduguard(int argc, char *const *argv) return set_port_cfg(bpdu_guard_port, getyesno(argv[3], "yes", "no")); } +static int cmd_setportnetwork(int argc, char *const *argv) +{ + int br_index = get_index(argv[1], "bridge"); + if (0 > br_index) + return br_index; + int port_index = get_index(argv[2], "port"); + if (0 > port_index) + return port_index; + return set_port_cfg(network_port, getyesno(argv[3], "yes", "no")); +} + +static int cmd_setportdonttxmt(int argc, char *const *argv) +{ + int br_index = get_index(argv[1], "bridge"); + if (0 > br_index) + return br_index; + int port_index = get_index(argv[2], "port"); + if (0 > port_index) + return port_index; + return set_port_cfg(dont_txmt, getyesno(argv[3], "yes", "no")); +} + static int cmd_settreeportprio(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); @@ -1530,6 +1566,10 @@ static const struct command commands[] = {4, 0, "settreeportcost", cmd_settreeportcost, " ", "Set port internal path cost for the given MSTI (0 = auto)"}, + {3, 0, "setportnetwork", cmd_setportnetwork, + " {yes|no}", "Set port network state"}, + {3, 0, "setportdonttxmt", cmd_setportdonttxmt, + " {yes|no}", "Disable/Enable sending BPDU"}, /* Other */ {1, 0, "debuglevel", cmd_debuglevel, "", "Level of verbosity"}, @@ -1554,7 +1594,8 @@ static void command_helpall(void) for(i = 0; i < COUNT_OF(commands); ++i) { - printf("-%s:\n %-16s %s\n", commands[i].help, commands[i].name, + if(strcmp("setportdonttxmt", commands[i].name)) + printf("-%s:\n %-16s %s\n", commands[i].help, commands[i].name, commands[i].format); } } diff --git a/mstp.c b/mstp.c index 012100f..8371a8b 100644 --- a/mstp.c +++ b/mstp.c @@ -50,6 +50,7 @@ static void br_state_machines_begin(bridge_t *br); static void prt_state_machines_begin(port_t *prt); static void tree_state_machines_begin(tree_t *tree); static void br_state_machines_run(bridge_t *br); +static void updtbrAssuRcvdInfoWhile(port_t *prt); #define FOREACH_PORT_IN_BRIDGE(port, bridge) \ list_for_each_entry((port), &(bridge)->ports, br_list) @@ -62,7 +63,11 @@ static void br_state_machines_run(bridge_t *br); /* 17.20.11 of 802.1D */ #define rstpVersion(br) ((br)->ForceProtocolVersion >= protoRSTP) - +/* Bridge assurance is operational only when NetworkPort type is configured + * and the operation status is pointToPoint and version is RSTP/MSTP + */ +#define assurancePort(prt) ((prt)->NetworkPort && (prt)->operPointToPointMAC \ + && (prt)->sendRSTP) /* * Recalculate configuration digest. (13.7) */ @@ -246,6 +251,10 @@ bool MSTP_IN_port_create_and_add_tail(port_t *prt, __u16 portno) prt->BpduGuardPort = false; prt->BpduGuardError = false; assign(prt->rapidAgeingWhile, 0u); + assign(prt->brAssuRcvdInfoWhile, 0u); + prt->NetworkPort = false; + prt->BaInconsistent = false; + prt->dontTxmtBpdu = false; prt->deleted = false; /* The following are initialized in BEGIN state: @@ -415,7 +424,13 @@ void MSTP_IN_set_port_enable(port_t *prt, bool up, int speed, int duplex) { prt->portEnabled = true; prt->BpduGuardError = false; + prt->BaInconsistent = false; changed = true; + /* When port is enabled, initialize bridge assurance timer, + * so that enough time is given before port is put in + * inconsistent state. + */ + updtbrAssuRcvdInfoWhile(prt); } } else @@ -575,6 +590,14 @@ bpdu_validation_failed: assign(prt->rcvdBpduData, *bpdu); prt->rcvdBpdu = true; + /* Reset bridge assurance on receipt of valid BPDU */ + if(prt->BaInconsistent) + { + prt->BaInconsistent = false; + INFO_PRTNAME(br, prt, "Clear Bridge assurance inconsistency"); + } + updtbrAssuRcvdInfoWhile(prt); + br_state_machines_run(br); } @@ -888,6 +911,8 @@ void MSTP_IN_get_cist_port_status(port_t *prt, CIST_PortStatus *status) assign(status->internal_port_path_cost, cist->InternalPortPathCost); status->bpdu_guard_port = prt->BpduGuardPort; status->bpdu_guard_error = prt->BpduGuardError; + status->network_port = prt->NetworkPort; + status->ba_inconsistent = prt->BaInconsistent; } /* 12.8.2.2 Read MSTI Port Parameters */ @@ -1022,6 +1047,33 @@ int MSTP_IN_set_cist_port_config(port_t *prt, CIST_PortConfig *cfg) } } + if(cfg->set_network_port) + { + if(prt->NetworkPort != cfg->network_port) + { + prt->NetworkPort = cfg->network_port; + INFO_PRTNAME(br, prt, "NetworkPort new=%d", prt->NetworkPort); + /* When Network port config is removed and bridge assurance + * inconsistency is set, clear the inconsistency. + */ + if(!prt->NetworkPort && prt->BaInconsistent) + { + prt->BaInconsistent = false; + INFO_PRTNAME(br, prt, "Clear Bridge assurance inconsistency"); + } + changed = true; + } + } + + if(cfg->set_dont_txmt) + { + if(prt->dontTxmtBpdu != cfg->dont_txmt) + { + prt->dontTxmtBpdu = cfg->dont_txmt; + INFO_PRTNAME(br, prt, "donttxmt new=%d", prt->dontTxmtBpdu); + } + } + if(changed && prt->portEnabled) br_state_machines_run(prt->bridge); @@ -2138,7 +2190,7 @@ static void txConfig(port_t *prt) bpdu_t b; per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); - if(prt->deleted) + if(prt->deleted || prt->dontTxmtBpdu) return; b.protocolIdentifier = 0; @@ -2198,7 +2250,7 @@ static void txMstp(port_t *prt) per_tree_port_t *ptp; msti_configuration_message_t *msti_msg; - if(prt->deleted) + if(prt->deleted || prt->dontTxmtBpdu) return; b.protocolIdentifier = 0; @@ -2296,7 +2348,7 @@ static void txTcn(port_t *prt) { bpdu_t b; - if(prt->deleted) + if(prt->deleted || prt->dontTxmtBpdu) return; b.protocolIdentifier = 0; @@ -2332,6 +2384,14 @@ static void updtRcvdInfoWhile(per_tree_port_t *ptp) ptp->rcvdInfoWhile = 0; } +static void updtbrAssuRcvdInfoWhile(port_t *prt) +{ + per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); + unsigned int Hello_Time = cist->portTimes.Hello_Time; + + prt->brAssuRcvdInfoWhile = 3 * cist->portTimes.Hello_Time; +} + /* 13.26.24 updtRolesDisabledTree */ static void updtRolesDisabledTree(tree_t *tree) { @@ -2608,6 +2668,8 @@ static void PTSM_tick(port_t *prt) --(prt->edgeDelayWhile); if(prt->txCount) --(prt->txCount); + if(prt->brAssuRcvdInfoWhile) + --(prt->brAssuRcvdInfoWhile); FOREACH_PTP_IN_PORT(ptp, prt) { @@ -3024,7 +3086,9 @@ static bool PTSM_run(port_t *prt, bool dry_run) return false; if(prt->sendRSTP) { /* implement MSTP */ - if(prt->newInfo || (prt->newInfoMsti && !mstiMasterPort)) + if(prt->newInfo || (prt->newInfoMsti && !mstiMasterPort) + || assurancePort(prt) + ) { if(dry_run) /* state change */ return true; @@ -4221,8 +4285,10 @@ static bool PRTSM_runr(per_tree_port_t *ptp, bool recursive_call, bool dry_run) PRTSM_to_DESIGNATED_PROPOSE(ptp); return false; } + /* Dont transition to learn/forward when BA inconsistent */ if(((0 == ptp->fdWhile) || ptp->agreed || prt->operEdge) && ((0 == ptp->rrWhile) || !ptp->reRoot) && !ptp->sync + && !ptp->port->BaInconsistent ) { if(!ptp->learn) @@ -4240,9 +4306,11 @@ static bool PRTSM_runr(per_tree_port_t *ptp, bool recursive_call, bool dry_run) return false; } } + /* Transition to discarding when BA inconsistent */ if(((ptp->sync && !ptp->synced) || (ptp->reRoot && (0 != ptp->rrWhile)) || ptp->disputed + || ptp->port->BaInconsistent ) && !prt->operEdge && (ptp->learn || ptp->forward) ) @@ -4769,6 +4837,20 @@ static bool __br_state_machines_run(bridge_t *br, bool dry_run) per_tree_port_t *ptp; tree_t *tree; + /* Check if bridge assurance timer expires */ + FOREACH_PORT_IN_BRIDGE(prt, br) + { + if(prt->portEnabled && assurancePort(prt) + && (0 == prt->brAssuRcvdInfoWhile) && !prt->BaInconsistent + ) + { + if(dry_run) /* state change */ + return true; + prt->BaInconsistent = true; + ERROR_PRTNAME(prt->bridge, prt, "Bridge assurance inconsistent"); + } + } + /* 13.28 Port Receive state machine */ FOREACH_PORT_IN_BRIDGE(prt, br) { diff --git a/mstp.h b/mstp.h index 4eec4aa..31d42e2 100644 --- a/mstp.h +++ b/mstp.h @@ -474,8 +474,12 @@ typedef struct bool AutoEdge; /* 13.22.m */ bool BpduGuardPort; bool BpduGuardError; + bool NetworkPort; + bool BaInconsistent; + bool dontTxmtBpdu; unsigned int rapidAgeingWhile; + unsigned int brAssuRcvdInfoWhile; /* State machines */ PRSM_states_t PRSM_state; @@ -686,6 +690,8 @@ typedef struct __u32 internal_port_path_cost; /* not in standard */ bool bpdu_guard_port; bool bpdu_guard_error; + bool network_port; + bool ba_inconsistent; } CIST_PortStatus; void MSTP_IN_get_cist_port_status(port_t *prt, CIST_PortStatus *status); @@ -740,6 +746,12 @@ typedef struct bool bpdu_guard_port; bool set_bpdu_guard_port; + + bool network_port; + bool set_network_port; + + bool dont_txmt; + bool set_dont_txmt; } CIST_PortConfig; int MSTP_IN_set_cist_port_config(port_t *prt, CIST_PortConfig *cfg);