stpm.c
上传用户:allwinjm
上传日期:2021-08-29
资源大小:99k
文件大小:8k
源码类别:

Internet/IE编程

开发平台:

Unix_Linux

  1. /************************************************************************ 
  2.  * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) 
  3.  * Copyright (C) 2001-2003 Optical Access 
  4.  * Author: Alex Rozin 
  5.  * 
  6.  * This file is part of RSTP library. 
  7.  * 
  8.  * RSTP library is free software; you can redistribute it and/or modify it 
  9.  * under the terms of the GNU Lesser General Public License as published by the 
  10.  * Free Software Foundation; version 2.1 
  11.  * 
  12.  * RSTP library is distributed in the hope that it will be useful, but 
  13.  * WITHOUT ANY WARRANTY; without even the implied warranty of 
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser 
  15.  * General Public License for more details. 
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public License 
  18.  * along with RSTP library; see the file COPYING.  If not, write to the Free 
  19.  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
  20.  * 02111-1307, USA. 
  21.  **********************************************************************/
  22.  /* STP machine instance : bridge per VLAN: 17.17 */
  23.  
  24. #include "base.h"
  25. #include "stpm.h"
  26. #include "stp_to.h" /* for STP_OUT_flush_lt */
  27. static STPM_T *bridges = NULL;
  28. static int
  29. _stp_stpm_init_machine (STATE_MACH_T* this)
  30. {
  31.   this->State = BEGIN;
  32.   (*(this->concreteEnterState)) (this);
  33.   return 0;
  34. }
  35. static int
  36. _stp_stpm_iterate_machines (STPM_T* this,
  37.                            int (*iter_callb) (STATE_MACH_T*),
  38.                            Bool exit_on_non_zero_ret)
  39. {
  40.   register STATE_MACH_T* stater;
  41.   register PORT_T*       port;
  42.   int                    iret, mret = 0;
  43.   /* state machines per bridge */
  44.   for (stater = this->machines; stater; stater = stater->next) {
  45.     iret = (*iter_callb) (stater);
  46.     if (exit_on_non_zero_ret && iret)
  47.       return iret;
  48.     else
  49.       mret += iret;
  50.   }
  51.   /* state machines per port */
  52.   for (port = this->ports; port; port = port->next) {
  53.     for (stater = port->machines; stater; stater = stater->next) {
  54.       iret = (*iter_callb) (stater);
  55.       if (exit_on_non_zero_ret && iret)
  56.         return iret;
  57.       else
  58.         mret += iret;
  59.     }
  60.   }
  61.   
  62.   return mret;
  63. }
  64. void
  65. _stp_stpm_init_data (STPM_T* this)
  66. {
  67.   STP_VECT_create (&this->rootPrio,
  68.                    &this->BrId,
  69.                    0,
  70.                    &this->BrId,
  71.                    0, 0);
  72.   this->BrTimes.MessageAge = 0;
  73.   STP_copy_times (&this->rootTimes, &this->BrTimes);
  74. }
  75. static unsigned char
  76. _check_topoch (STPM_T* this)
  77. {
  78.   register PORT_T*  port;
  79.   
  80.   for (port = this->ports; port; port = port->next) {
  81.     if (port->tcWhile) {
  82.       return 1;
  83.     }
  84.   }
  85.   return 0;
  86. }
  87. void
  88. STP_stpm_one_second (STPM_T* param)
  89. {
  90.   STPM_T*           this = (STPM_T*) param;
  91.   register PORT_T*  port;
  92.   register int      iii;
  93.   if (STP_ENABLED != this->admin_state) return;
  94.   for (port = this->ports; port; port = port->next) {
  95.     for (iii = 0; iii < TIMERS_NUMBER; iii++) {
  96.       if (*(port->timers[iii]) > 0) {
  97.         (*port->timers[iii])--;
  98.       }
  99.     }    
  100.     port->uptime++;
  101.   }
  102.   STP_stpm_update (this);
  103.   this->Topo_Change = _check_topoch (this);
  104.   if (this->Topo_Change) {
  105.     this->Topo_Change_Count++;
  106.     this->timeSince_Topo_Change = 0;
  107.   } else {
  108.     this->Topo_Change_Count = 0;
  109.     this->timeSince_Topo_Change++;
  110.   }
  111. }
  112. STPM_T*
  113. STP_stpm_create (int vlan_id, char* name)
  114. {
  115.   STPM_T* this;
  116.   STP_NEW_IN_LIST(this, STPM_T, bridges, "stp instance");
  117.   this->admin_state = STP_DISABLED;
  118.   
  119.   this->vlan_id = vlan_id;
  120.   if (name) {
  121.     STP_STRDUP(this->name, name, "stp bridge name");
  122.   }
  123.   this->machines = NULL;
  124.   this->ports = NULL;
  125.   STP_STATE_MACH_IN_LIST(rolesel);
  126. #ifdef STP_DBG
  127.   /* this->rolesel->debug = 2;  */
  128. #endif
  129.   return this;
  130. }
  131. int
  132. STP_stpm_enable (STPM_T* this, UID_STP_MODE_T admin_state)
  133. {
  134.   int rc = 0;
  135.   if (admin_state == this->admin_state) {
  136.     /* nothing to do :) */
  137.     return 0;
  138.   }
  139.   if (STP_ENABLED == admin_state) {
  140.     rc = STP_stpm_start (this);
  141.     this->admin_state = admin_state;
  142.   } else {
  143.     this->admin_state = admin_state;
  144.     STP_stpm_stop (this);
  145.   }
  146.   
  147.   return rc;
  148. }
  149. void
  150. STP_stpm_delete (STPM_T* this)
  151. {
  152.   register STPM_T*       tmp;
  153.   register STPM_T*       prev;
  154.   register STATE_MACH_T* stater;
  155.   register PORT_T*       port;
  156.   register void*         pv;
  157.   STP_stpm_enable (this, STP_DISABLED);
  158.   
  159.   for (stater = this->machines; stater; ) {
  160.     pv = (void*) stater->next;
  161.     STP_state_mach_delete (stater);
  162.     this->machines = stater = (STATE_MACH_T*) pv;
  163.   }
  164.   for (port = this->ports; port; ) {
  165.     pv = (void*) port->next;
  166.     STP_port_delete (port);
  167.     this->ports = port = (PORT_T*) pv;
  168.   }
  169.   prev = NULL;
  170.   for (tmp = bridges; tmp; tmp = tmp->next) {
  171.     if (tmp->vlan_id == this->vlan_id) {
  172.       if (prev) {
  173.         prev->next = this->next;
  174.       } else {
  175.         bridges = this->next;
  176.       }
  177.       
  178.       if (this->name)
  179.         STP_FREE(this->name, "stp bridge name");
  180.       STP_FREE(this, "stp instance");
  181.       break;
  182.     }
  183.     prev = tmp;
  184.   }
  185. }
  186. int
  187. STP_stpm_start (STPM_T* this)
  188. {
  189.   register PORT_T* port;
  190.   if (! this->ports) { /* there are not any ports :( */
  191.     return STP_There_Are_No_Ports;
  192.   }
  193.   if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */
  194.     return STP_Cannot_Compute_Bridge_Prio;
  195.   }
  196.   /* check, that the stpm has unique bridge Id */
  197.   if (0 != STP_stpm_check_bridge_priority (this)) {
  198.     /* there is an enabled bridge with same ID :( */
  199.     return STP_Invalid_Bridge_Priority;
  200.   }
  201.   _stp_stpm_init_data (this);
  202.   for (port = this->ports; port; port = port->next) {
  203.     STP_port_init (port, this, True);
  204.   }
  205. #ifndef STRONGLY_SPEC_802_1W
  206.   /* A. see comment near STRONGLY_SPEC_802_1W in topoch.c */
  207.   /* B. port=0 here means: delete for all ports */
  208. #ifdef STP_DBG
  209.   stp_trace("%s (all, start stpm)",
  210.         "clearFDB");
  211. #endif
  212.   STP_OUT_flush_lt (0, this->vlan_id, LT_FLASH_ONLY_THE_PORT, "start stpm");
  213. #endif
  214.   _stp_stpm_iterate_machines (this, _stp_stpm_init_machine, False);
  215.   STP_stpm_update (this);
  216.   return 0;
  217. }
  218. void
  219. STP_stpm_stop (STPM_T* this)
  220. {
  221. }
  222. int
  223. STP_stpm_update (STPM_T* this) /* returns number of loops */
  224. {
  225.   register Bool     need_state_change;
  226.   register int      number_of_loops = 0;
  227.   need_state_change = False; 
  228.   
  229.   for (;;) {/* loop until not need changes */
  230.     need_state_change = _stp_stpm_iterate_machines (this,
  231.                                                    STP_check_condition,
  232.                                                    True);
  233.     if (! need_state_change) return number_of_loops;
  234.     number_of_loops++;
  235.     /* here we know, that at least one stater must be
  236.        updated (it has changed state) */
  237.     number_of_loops += _stp_stpm_iterate_machines (this,
  238.                                                   STP_change_state,
  239.                                                   False);
  240.   }
  241.   return number_of_loops;
  242. }
  243. BRIDGE_ID *
  244. STP_compute_bridge_id (STPM_T* this)
  245. {
  246.   register PORT_T* port;
  247.   register PORT_T* min_num_port;
  248.   int              port_index = 0;
  249.   for (port = this->ports; port; port = port->next) {
  250.     if (! port_index || port->port_index < port_index) {
  251.       min_num_port = port;
  252.       port_index = port->port_index;
  253.     }
  254.   }
  255.   if (! min_num_port) return NULL; /* IMHO, it may not be */
  256.   STP_OUT_get_port_mac (min_num_port->port_index, this->BrId.addr);
  257.   return &this->BrId;
  258. }
  259. STPM_T*
  260. STP_stpm_get_the_list (void)
  261. {
  262.   return bridges;
  263. }
  264. void
  265. STP_stpm_update_after_bridge_management (STPM_T* this)
  266. {
  267.   register PORT_T* port;
  268.   for (port = this->ports; port; port = port->next) {
  269.     port->reselect = True;
  270.     port->selected = False;
  271.   }
  272. }
  273. int
  274. STP_stpm_check_bridge_priority (STPM_T* this)
  275. {
  276.   register STPM_T* oth;
  277.   for (oth = bridges; oth; oth = oth->next) {
  278.     if (STP_ENABLED == oth->admin_state && oth != this &&
  279.         ! STP_VECT_compare_bridge_id (&this->BrId, &oth->BrId)) {
  280.       return STP_Invalid_Bridge_Priority;
  281.     }
  282.   }
  283.   return 0;
  284. }
  285. const char*
  286. STP_stpm_get_port_name_by_id (STPM_T* this, PORT_ID port_id)
  287. {
  288.   register PORT_T* port;
  289.   for (port = this->ports; port; port = port->next) {
  290.     if (port_id == port->port_id) {
  291.         return port->port_name;
  292.     }
  293.   }
  294.   return "Undef?";
  295. }