Some changes have been made to RSTPLIB version rsttplib.1.1.0.2 for use in this program. The changes are given in the following diff. The changes fall into 3 categories: 1. Changes to support dynamic addition and deletion of bridge ports. 2. Changes to support multiple bridges. 3. Fixes to protocol part based on 802.1w conformance testing results. diff -Naur rstplib.1.1.02/base.h rstplib/base.h --- rstplib.1.1.02/base.h 2002-01-20 00:33:22.000000000 -0800 +++ rstplib/base.h 2006-10-26 13:43:15.000000000 -0700 @@ -75,6 +75,7 @@ CHOOSE(STP_Imlicite_Instance_Create_Failed), \ CHOOSE(STP_Small_Bridge_Priority), \ CHOOSE(STP_Large_Bridge_Priority), \ + CHOOSE(STP_Bridge_Priority_Not_A_Multiple_Of_4096), \ CHOOSE(STP_Small_Hello_Time), \ CHOOSE(STP_Large_Hello_Time), \ CHOOSE(STP_Small_Max_Age), \ @@ -83,6 +84,10 @@ CHOOSE(STP_Large_Forward_Delay), \ CHOOSE(STP_Forward_Delay_And_Max_Age_Are_Inconsistent),\ CHOOSE(STP_Hello_Time_And_Max_Age_Are_Inconsistent), \ + CHOOSE(STP_Small_Port_Priority), \ + CHOOSE(STP_Large_Port_Priority), \ + CHOOSE(STP_Port_Priority_Not_A_Multiple_Of_16), \ + CHOOSE(STP_Large_Port_PCost), \ CHOOSE(STP_Vlan_Had_Not_Yet_Been_Created), \ CHOOSE(STP_Port_Is_Absent_In_The_Vlan), \ CHOOSE(STP_Big_len8023_Format), \ @@ -176,11 +181,11 @@ /* for debug trace messages */ -#ifdef __LINUX__ +#ifdef __LINUX__USE_PRINTF_FOR_STRACE extern char* sprint_time_stump (void); #define stp_trace(F, B...) printf("%s:" F "\n", sprint_time_stump(), ##B) #else -extern ULONG stp_trace (const char* fmt, ...); +extern void stp_trace (const char* fmt, ...); #endif #endif /* _STP_BASE_H__ */ diff -Naur rstplib.1.1.02/pcost.c rstplib/pcost.c --- rstplib.1.1.02/pcost.c 2002-01-20 00:34:09.000000000 -0800 +++ rstplib/pcost.c 2006-10-20 16:04:16.000000000 -0700 @@ -70,8 +70,10 @@ } static void -updPortPathCost (STATE_MACH_T *this) +updPortPathCost (PORT_T *port) { + port->reselect = True; + port->selected = False; } void @@ -97,7 +99,7 @@ port->usedSpeed = -1; break; case STABLE: - updPortPathCost (this); + updPortPathCost (port); break; } } diff -Naur rstplib.1.1.02/port.c rstplib/port.c --- rstplib.1.1.02/port.c 2002-01-20 00:34:10.000000000 -0800 +++ rstplib/port.c 2006-10-20 16:04:16.000000000 -0700 @@ -139,10 +139,10 @@ this->port_id, this->port_id); STP_copy_times (&this->designTimes, &stpm->rootTimes); + this->fdWhile = 0; } /* reset timers */ - this->fdWhile = this->helloWhen = this->mdelayWhile = this->rbWhile = diff -Naur rstplib.1.1.02/portinfo.c rstplib/portinfo.c --- rstplib.1.1.02/portinfo.c 2002-01-20 00:34:10.000000000 -0800 +++ rstplib/portinfo.c 2006-10-20 16:04:16.000000000 -0700 @@ -75,6 +75,12 @@ if (BPDU_RSTP == port->msgBpduType) { port->msgPortRole = (port->msgFlags & PORT_ROLE_MASK) >> PORT_ROLE_OFFS; +#ifndef ORIG + if (RSTP_PORT_ROLE_UNKN == port->msgPortRole) { + port->msgBpduVersion = FORCE_STP_COMPAT; + port->msgBpduType = BPDU_CONFIG_TYPE; + } +#endif } if (RSTP_PORT_ROLE_DESGN == port->msgPortRole || @@ -109,10 +115,14 @@ } } - if (RSTP_PORT_ROLE_ROOT == port->msgBpduType && + if (RSTP_PORT_ROLE_ROOT == port->msgPortRole && port->operPointToPointMac && + ! STP_VECT_compare_bridge_id (&port->msgPrio.root_bridge, + &port->portPrio.root_bridge) && + port->msgPrio.root_path_cost == port->portPrio.root_path_cost && ! STP_VECT_compare_bridge_id (&port->msgPrio.design_bridge, &port->portPrio.design_bridge) && + port->msgPrio.design_port == port->portPrio.design_port && AGREEMENT_BIT & port->msgFlags) { #ifdef STP_DBG if (this->debug) { diff -Naur rstplib.1.1.02/stp_in.c rstplib/stp_in.c --- rstplib.1.1.02/stp_in.c 2002-01-20 00:34:13.000000000 -0800 +++ rstplib/stp_in.c 2006-10-20 16:04:16.000000000 -0700 @@ -170,6 +170,11 @@ return STP_Large_Bridge_Priority; } + if (uid_cfg->bridge_priority & ~MASK_BR_PRIO) { + stp_trace ("%d bridge_priority must be a multiple of 4096", (int) uid_cfg->bridge_priority); + return STP_Bridge_Priority_Not_A_Multiple_Of_4096; + } + if (uid_cfg->hello_time < MIN_BR_HELLOT) { stp_trace ("%d hello_time small", (int) uid_cfg->hello_time); return STP_Small_Hello_Time; @@ -815,8 +820,13 @@ return 0; } +#ifdef ORIG int STP_IN_set_port_cfg (IN int vlan_id, IN UID_STP_PORT_CFG_T* uid_cfg) +#else +int +STP_IN_set_port_cfg (int vlan_id, int port_index, UID_STP_PORT_CFG_T* uid_cfg) +#endif { register STPM_T* this; register PORT_T* port; @@ -831,12 +841,21 @@ return STP_Vlan_Had_Not_Yet_Been_Created; } +#ifdef ORIG for (port_no = 1; port_no <= max_port; port_no++) { if (! BitmapGetBit(&uid_cfg->port_bmp, port_no - 1)) continue; +#else + port_no = port_index; + { +#endif port = _stpapi_port_find (this, port_no); if (! port) {/* port is absent in the stpm :( */ +#ifdef ORIG continue; +#else + return STP_Port_Is_Absent_In_The_Vlan; +#endif } if (PT_CFG_MCHECK & uid_cfg->field_mask) { @@ -845,10 +864,18 @@ } if (PT_CFG_COST & uid_cfg->field_mask) { + if (uid_cfg->admin_port_path_cost > MAX_PORT_PCOST) + return STP_Large_Port_PCost; port->adminPCost = uid_cfg->admin_port_path_cost; } if (PT_CFG_PRIO & uid_cfg->field_mask) { + if (uid_cfg->port_priority < MIN_PORT_PRIO) + return STP_Small_Port_Priority; + if (uid_cfg->port_priority > MAX_PORT_PRIO) + return STP_Large_Port_Priority; + if (uid_cfg->port_priority & ~MASK_PORT_PRIO) + return STP_Port_Priority_Not_A_Multiple_Of_16; port->port_id = (uid_cfg->port_priority << 8) + port_no; } @@ -955,3 +982,114 @@ return rstp_error_names[rstp_err_no]; } +/*---------------- Dynamic port create / delete ------------------*/ + +int STP_IN_port_create(int vlan_id, int port_index) +{ + register STPM_T* this; + + this = stpapi_stpm_find (vlan_id); + + if (! this) { /* can't create stpm :( */ + return STP_Vlan_Had_Not_Yet_Been_Created; + } + + PORT_T *port = STP_port_create (this, port_index); + if (! port) { + /* can't add port :( */ + stp_trace ("can't create port %d", (int) port_index); + return STP_Cannot_Create_Instance_For_Port; + } + STP_port_init(port, this, True); + + STP_compute_bridge_id(this); + STP_stpm_update_after_bridge_management (this); + STP_stpm_update (this); + return 0; +} + +int STP_IN_port_delete(int vlan_id, int port_index) +{ + register STPM_T* this; + PORT_T *port; + + this = stpapi_stpm_find (vlan_id); + + if (! this) { /* can't find stpm :( */ + return STP_Vlan_Had_Not_Yet_Been_Created; + } + + port = _stpapi_port_find (this, port_index); + if (! port) { + return STP_Port_Is_Absent_In_The_Vlan; + } + + STP_port_delete (port); + + STP_compute_bridge_id(this); + STP_stpm_update_after_bridge_management (this); + STP_stpm_update (this); + return 0; +} + + +/*--- For multiple STP instances - non multithread use ---*/ + +struct stp_instance +{ + STPM_T *bridges; +#ifdef STP_DBG + int dbg_rstp_deny; +#endif + int max_port; /* Remove this */ + int nev; + RSTP_EVENT_T tev; +}; + +struct stp_instance *STP_IN_instance_create(void) +{ + struct stp_instance *p; + p = malloc(sizeof(*p)); + if (!p) return p; + p->bridges = NULL; +#ifdef STP_DBG + p->dbg_rstp_deny = 0; +#endif + p->max_port = 1024; + p->tev = RSTP_EVENT_LAST_DUMMY; + p->nev = 0; + return p; +} + +void STP_IN_instance_begin(struct stp_instance *p) +{ + bridges = p->bridges; +#ifdef STP_DBG + dbg_rstp_deny = p->dbg_rstp_deny; +#endif + max_port = p->max_port; + tev = p->tev; + nev = p->nev; +} + +void STP_IN_instance_end(struct stp_instance *p) +{ + p->bridges = bridges; +#ifdef STP_DBG + p->dbg_rstp_deny = dbg_rstp_deny; +#endif + p->max_port = max_port; + p->tev = tev; + p->nev = nev; +} + +void STP_IN_instance_delete(struct stp_instance *p) +{ + STP_IN_instance_begin(p); + STP_IN_delete_all(); + STP_IN_instance_end(p); + free(p); +} + + + diff -Naur rstplib.1.1.02/stp_in.h rstplib/stp_in.h --- rstplib.1.1.02/stp_in.h 2002-01-20 00:33:52.000000000 -0800 +++ rstplib/stp_in.h 2006-10-20 16:04:16.000000000 -0700 @@ -56,6 +56,7 @@ #define DEF_BR_PRIO 32768 #define MIN_BR_PRIO 0 #define MAX_BR_PRIO 61440 +#define MASK_BR_PRIO 0xf000 #define DEF_BR_HELLOT 2 #define MIN_BR_HELLOT 1 @@ -76,12 +77,15 @@ #define DEF_PORT_PRIO 128 #define MIN_PORT_PRIO 0 #define MAX_PORT_PRIO 240 /* in steps of 16 */ +#define MASK_PORT_PRIO 0xf0 #define DEF_ADMIN_NON_STP False #define DEF_ADMIN_EDGE True #define DEF_LINK_DELAY 3 /* see edge.c */ #define DEF_P2P P2P_AUTO +#define MAX_PORT_PCOST 200000000 + /* Section 1: Create/Delete/Start/Stop the RSTP instance */ void /* init the engine */ @@ -101,6 +105,12 @@ int STP_IN_delete_all (void); +/* Port create/delete */ + +int STP_IN_port_create(int vlan_id, int port_index); + +int STP_IN_port_delete(int vlan_id, int port_index); + /* Section 2. "Get" management */ Bool @@ -136,9 +146,15 @@ BITMAP_T* port_bmp, UID_STP_CFG_T* uid_cfg); +#ifdef ORIG int STP_IN_set_port_cfg (int vlan_id, UID_STP_PORT_CFG_T* uid_cfg); +#else +int +STP_IN_set_port_cfg (int vlan_id, int port_index, + UID_STP_PORT_CFG_T* uid_cfg); +#endif #ifdef STP_DBG int STP_IN_dbg_set_port_trace (char* mach_name, int enadis, @@ -168,6 +184,19 @@ STP_IN_rx_bpdu (int vlan_id, int port_index, BPDU_T* bpdu, size_t len); #endif +/*--- For multiple STP instances - non multithread use ---*/ + +struct stp_instance; +/* Create struct to hold STP instance state and initialize it. + A copy of all global state in the library. */ +struct stp_instance *STP_IN_instance_create(void); +/* Set context from this STP instance */ +void STP_IN_instance_begin(struct stp_instance *p); +/* Save context back to this STP instance */ +void STP_IN_instance_end(struct stp_instance *p); +/* Delete this STP instance */ +void STP_IN_instance_delete(struct stp_instance *p); + #ifdef _STP_MACHINE_H__ /* Inner usage definitions & functions */ diff -Naur rstplib.1.1.02/stp_state.h rstplib/stp_state.h --- rstplib.1.1.02/stp_state.h 1969-12-31 16:00:00.000000000 -0800 +++ rstplib/stp_state.h 2006-10-20 16:04:16.000000000 -0700 @@ -0,0 +1,7 @@ +#ifndef _STP_STATE_H__ +#define _STP_STATE_H__ + + + + +#endif diff -Naur rstplib.1.1.02/stpm.c rstplib/stpm.c --- rstplib.1.1.02/stpm.c 2002-01-20 00:34:14.000000000 -0800 +++ rstplib/stpm.c 2006-10-30 19:21:51.000000000 -0800 @@ -26,7 +26,11 @@ #include "stpm.h" #include "stp_to.h" /* for STP_OUT_flush_lt */ -static STPM_T *bridges = NULL; +/*static*/ STPM_T *bridges = NULL; + +/* We can flush learned fdb by port, so set this in stpm.c and topoch.c */ +/* This doesn't seem to solve the topology change problems. Don't use it yet */ +//#define STRONGLY_SPEC_802_1W static int _stp_stpm_init_machine (STATE_MACH_T* this) @@ -217,9 +221,11 @@ { register PORT_T* port; +#ifdef ORIG if (! this->ports) { /* there are not any ports :( */ return STP_There_Are_No_Ports; } +#endif if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */ return STP_Cannot_Compute_Bridge_Prio; @@ -289,19 +295,16 @@ STP_compute_bridge_id (STPM_T* this) { register PORT_T* port; - register PORT_T* min_num_port; - int port_index = 0; + unsigned char old[6], new[6]; + memset(&old, 0xff, sizeof(old)); for (port = this->ports; port; port = port->next) { - if (! port_index || port->port_index < port_index) { - min_num_port = port; - port_index = port->port_index; - } + STP_OUT_get_port_mac (port->port_index, new); + if (memcmp(new, old, sizeof(old)) < 0) + memcpy(old, new, sizeof(old)); } - if (! min_num_port) return NULL; /* IMHO, it may not be */ - - STP_OUT_get_port_mac (min_num_port->port_index, this->BrId.addr); + memcpy(this->BrId.addr, old, sizeof(old)); return &this->BrId; } diff -Naur rstplib.1.1.02/stpm.h rstplib/stpm.h --- rstplib.1.1.02/stpm.h 2002-01-20 00:33:54.000000000 -0800 +++ rstplib/stpm.h 2006-10-20 16:04:16.000000000 -0700 @@ -103,6 +103,8 @@ STPM_T * STP_stpm_get_the_list (void); +extern STPM_T *bridges; + void STP_stpm_update_after_bridge_management (STPM_T* this); diff -Naur rstplib.1.1.02/stpmgmt.c rstplib/stpmgmt.c --- rstplib.1.1.02/stpmgmt.c 2002-01-20 00:34:14.000000000 -0800 +++ rstplib/stpmgmt.c 2006-10-20 16:04:16.000000000 -0700 @@ -50,6 +50,11 @@ this->BrTimes.ForwardDelay = init_cfg.forward_delay; this->ForceVersion = (PROTOCOL_VERSION_T) init_cfg.force_version; } +#ifdef ORIG +#else + if (this->admin_state != STP_ENABLED) + err_code = STP_stpm_enable(this, STP_ENABLED); +#endif RSTP_CRITICAL_PATH_END; return err_code; @@ -145,10 +150,11 @@ int STP_IN_delete_all (void) { - register STPM_T* stpm; + register STPM_T* stpm, *next; RSTP_CRITICAL_PATH_START; - for (stpm = STP_stpm_get_the_list (); stpm; stpm = stpm->next) { + for (stpm = STP_stpm_get_the_list (); stpm; stpm = next) { + next = stpm->next; STP_stpm_enable (stpm, STP_DISABLED); STP_stpm_delete (stpm); } diff -Naur rstplib.1.1.02/topoch.c rstplib/topoch.c --- rstplib.1.1.02/topoch.c 2002-01-20 00:34:16.000000000 -0800 +++ rstplib/topoch.c 2006-10-30 19:22:01.000000000 -0800 @@ -40,6 +40,10 @@ #define GET_STATE_NAME STP_topoch_get_state_name #include "choose.h" +/* We can flush learned fdb by port, so set this in stpm.c and topoch.c */ +/* This doesn't seem to solve the topology change problems. Don't use it yet */ +//#define STRONGLY_SPEC_802_1W + #ifndef STRONGLY_SPEC_802_1W /* * In many kinds of hardware the function @@ -61,12 +65,13 @@ if (this->debug) { stp_trace("%s (%s, %s, %s, '%s')", "flush", port->port_name, port->owner->name, - LT_FLASH_ONLY_THE_PORT == type ? "this port" : "other ports", + "this port", reason); } bret = STP_OUT_flush_lt (port->port_index, port->owner->vlan_id, LT_FLASH_ONLY_THE_PORT, reason); + return bret; } #endif @@ -103,7 +108,11 @@ if (port->sendRSTP && port->operPointToPointMac) { return 2 * port->owner->rootTimes.HelloTime; } +#ifdef ORIG return port->owner->rootTimes.MaxAge; +#else + return port->owner->rootTimes.MaxAge + port->owner->rootTimes.ForwardDelay; +#endif } void diff -Naur rstplib.1.1.02/transmit.c rstplib/transmit.c --- rstplib.1.1.02/transmit.c 2002-01-20 00:34:17.000000000 -0800 +++ rstplib/transmit.c 2006-10-20 16:04:16.000000000 -0700 @@ -99,7 +99,11 @@ { unsigned short len8023; +#ifdef ORIG STP_OUT_get_port_mac (port_index, bpdu_packet.mac.src_mac); +#else + /* Don't bother. LLC trasmits with correct source MAC, we don't supply it */ +#endif bpdu_packet.hdr.bpdu_type = bpdu_type; bpdu_packet.hdr.version = (BPDU_RSTP == bpdu_type) ? @@ -110,7 +114,11 @@ len8023 = htons ((unsigned short) (pkt_len + 3)); memcpy (&bpdu_packet.eth.len8023, &len8023, 2); +#ifdef ORIG if (pkt_len < MIN_FRAME_LENGTH) pkt_len = MIN_FRAME_LENGTH; +#else + /* Don't do this. LLC puts in 802.3 length based on what we transmit */ +#endif return pkt_len; } @@ -235,7 +243,7 @@ pkt_len = build_bpdu_header (port->port_index, BPDU_RSTP, - sizeof (BPDU_HEADER_T) + sizeof (BPDU_BODY_T) + 2); + sizeof (BPDU_HEADER_T) + sizeof (BPDU_BODY_T) + 1); build_config_bpdu (port, False); switch (port->selectedRole) { @@ -258,7 +266,12 @@ } bpdu_packet.body.flags |= (role << PORT_ROLE_OFFS); - +#ifndef ORIG + if (port->forwarding) + bpdu_packet.body.flags |= FORWARD_BIT; + if (port->learning) + bpdu_packet.body.flags |= LEARN_BIT; +#endif if (port->synced) { #if 0 /* def STP_DBG */ if (port->roletrns->debug)