⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stp_trunk.c

📁 stp代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/***********************************************************************
* Copyright (C) 2005,UNE Corporation.
* 
* File Name: stp_trunk.c
* File Mark: Spanning Tree interaction with trunking.  When 802.3ad
             type of trunk is formed on a switch, STP should treat
             the trunk as one logical port. Therefore, the individual
             physical ports within the trunk does not participate
             in STP, rather, the trunk as a whole participate
             int STP calculation.  The "trunk port" path cost
             should be decided considering the "trunk port"
             bandwidth is the sum of all the ports conprised of
             the trunk.
             
             To achieve this,  We turned off BPDU generation
             and reception on all but one port of the trunk group.
             Thus, effectively, the trunk as a whole runs STP.
* Description:  
* Others: 
 * Notes:
 *    Currently, this code does not work for multiple chip
 *    boards.  It only runs when all systems are single unit,
 *    in stacking mode, or standalone mode.
* Version: V1.0
* Author: 
* Date: 
* History 1:
*     Date: 
* 	  Version:
*     Author: 
*     Modification:  
* History 2: …
**********************************************************************/

#include <sal/user/sal.h>
#include <sal/user/io.h>

#include <soc/mem.h>
#include <soc/drv.h>
#include <soc/debug.h>

#include <bcm/error.h>
#include <bcm/port.h>
#include <bcm/pmux.h>
#include <bcm/trunk.h>
#include <bcm/stack.h>

#include <stacking/trace.h>
#include <stacking/stk_transport.h>
#include <stacking/stk_platform.h>
#include <stacking/simplex.h>
#include <stacking/chassis.h>
#include <stacking/rdp.h>

#include <stp/stp.h>
#include <stp/stp_api.h>
#include <stp/stp_appl.h>
#include <stp/stp_trunk.h>

/*
 * Global Variables
 */
extern int stp_stack_port;

/*
 * Local Variables
 */
static stp_trunk_t trunk_table[BCM_TRUNK_GROUP_MAX];
static int stp_trunk_initialized = FALSE;

/* 设计思想是这个模块仅仅管理STP链路信息,由聚合主端口ROOT参与生成树计算
 * 成员端口MEMBER时刻保持和主端口的状态一致;当聚合主端口链路DOWN的时候,
 * 重新选举一个活动的成员端口作为主端口参与生成树计算。 */
/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_init
* DESCRIPTION:初始化聚合表,用来存储聚合组的信息和状态。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

int
stp_trunk_init(uint16 trunk_id)
{
    int p; 

        for (p = 0; p < BCM_TRUNK_MAX_PORTCNT; p++) {
        trunk_table[trunk_id].port[p].num = 0;
        trunk_table[trunk_id].port[p].flag = 0;
    }
    trunk_table[trunk_id].port_count = 0;
    trunk_table[trunk_id].active_count = 0;
    trunk_table[trunk_id].rtag = BCM_TRUNK_PSC_DEFAULT;
    trunk_table[trunk_id].tree_id = 0;

    stp_trunk_initialized = TRUE;

    return (0);
    }


/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_init
* DESCRIPTION:初始化聚合表,用来存储聚合组的信息和状态。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

int
stp_print_trunk_table(void)
{
    int t, p,unit,port,gport; 
    printk("\n----------------------------------------------------\n");
    for (t = 0; t < BCM_TRUNK_GROUP_MAX; t++) {
    	  if(trunk_table[t].tree_id != 0)
    	  {
    	  	 printk("aggr :%d member:",t);
        for (p = 0; p < BCM_TRUNK_MAX_PORTCNT; p++) {
           	  if(trunk_table[t].port[p].num != 0){
           	  	unit = stp_port_l2unit(trunk_table[t].port[p].num);
           	  	port = stp_port_l2p(trunk_table[t].port[p].num);
           	  	gport = get_global_port(unit,port);
                printk(" %d ",gport); 
        }
           }
        printk("\n");
    }
    }
    printk("\n----------------------------------------------------\n");    
    return (0);
}

/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_clean_stport_info
* DESCRIPTION:当聚合被删除的时候,我们应该把生成树端口从聚合状态
*             转到普通的生成树状态。使能BPDU功能,参与生成树计算。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

void stp_trunk_clean_stport_info(stp_id_t tree_id,uint16 lport)
{
    spantree_t *stp;
    stp_port_t *stport;

    stp = stp_lookup_from_stp_id(tree_id);
    if (stp == NULL) {
        return;
    }	
    stport = stp_port_lookup_from_id(stp, lport);
    if (stport == NULL) {
        return;
    }

    stp_port_bpdu_enable(stp, stport->lport, 1);
    stport->path_cost = STP_PATH_COST_1GB;
    stport->link_flags &= ~STP_LF_TRUNKMEMBER;
    stport->link_flags &= ~STP_LF_TRUNKROOT;
    stport->tid = 0;  
    enable_port(stp, stport);      
    return;  
}
/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_cleanup
* DESCRIPTION:清除内存聚合表信息,并且改变聚合生成树端口的角色。
*             退出聚合,而生成树继续有效。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

int
stp_trunk_cleanup(uint16 trunk_id)
{
    int p,exist_any_aggr = 0;
    uint16 tree_id;
    tree_id = trunk_table[trunk_id].tree_id;
    if((tree_id == 0)||(tree_id > 4095)){
    	return -1;
    }
    if (stp_trunk_initialized == TRUE) {
            for (p = 0; p < BCM_TRUNK_MAX_PORTCNT; p++) {
            	  stp_trunk_clean_stport_info(tree_id,trunk_table[trunk_id].port[p].num);
                trunk_table[trunk_id].port[p].num = 0;
                trunk_table[trunk_id].port[p].flag = 0;
        }
            trunk_table[trunk_id].port_count = 0;
            trunk_table[trunk_id].active_count = 0;
            trunk_table[trunk_id].rtag = BCM_TRUNK_PSC_DEFAULT;
            trunk_table[trunk_id].tree_id = 0;

        for (p = 0; p< BCM_TRUNK_GROUP_MAX; p++) {
        	if(trunk_table[p].tree_id != 0){
        		exist_any_aggr = 1;
        		break;
        	}
        }
        if(!exist_any_aggr){
        stp_trunk_initialized = FALSE;
        }
    }
    return (0);
}

/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_cleanup
* DESCRIPTION:清除内存聚合表信息,并且改变聚合生成树端口的角色。
              退出生成树,而聚合继续有效。
* AUTHOR:ZHOUGUIS 2005-12-20
-------------------------------------------------------------------------------*/
void stp_trunk_clean_tree_info(stp_id_t tree_id)
{
    int p , p1;
    if (stp_trunk_initialized == TRUE) {
        for (p = 0; p < BCM_TRUNK_GROUP_MAX; p++) {
        	if(trunk_table[p].tree_id == tree_id){
            trunk_table[p].active_count = 0;            
            for (p1 = 0; p1 < BCM_TRUNK_MAX_PORTCNT; p1++) {
                trunk_table[p].port[p1].flag = 0;
            }                 		
        	}
        }
    }	
}
/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_init
* DESCRIPTION:初始化聚合表,用来存储聚合组的信息和状态。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

int
stp_trunk_running(void)
{
    return (stp_trunk_initialized);
}

/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_port_member
* DESCRIPTION:检查端口是否是聚合组tid成员。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

int
stp_trunk_port_member(bcm_trunk_t tid, int lport)
{
    int p;

    for (p = 0; p < BCM_TRUNK_MAX_PORTCNT; p++) {
        if (trunk_table[tid].port[p].num == lport) {
            return (1);
        }
    }

    return (0);
}


/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_is_trunk_port
* DESCRIPTION:检查端口是否是任何聚合组成员。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

int
stp_trunk_is_trunk_port(int lport)
{
    int t, p;

    for (t = 0; t < BCM_TRUNK_GROUP_MAX; t++) {
        for (p = 0; p < BCM_TRUNK_MAX_PORTCNT; p++) {
            if (trunk_table[t].port[p].num == lport) {
                return (1);
            }
        }
    }
    return (0);
}
/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_get_trunk_id
* DESCRIPTION:获取端口的聚合组ID,-1表示端口没有聚合组。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

int stp_trunk_get_trunk_id(int lport)
{
    int t, p;

    for (t = 0; t < BCM_TRUNK_GROUP_MAX; t++) {
        for (p = 0; p < BCM_TRUNK_MAX_PORTCNT; p++) {
            if (trunk_table[t].port[p].num == lport) {
                return (t);
        }
        }
    }
    return (-1);	
    }
/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_add_one_port
* DESCRIPTION:添加一个端口。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/

static int
stp_trunk_add_one_port(spantree_t *stp, bcm_trunk_t tid, int lport, int link_up)
{

    int pc, port, rtag;

        port = stp_port_l2p(lport);

    pc = trunk_table[tid].port_count;
    if (link_up == FALSE) {
        trunk_table[tid].port[pc].flag &= ~TRUNK_PORT_ACTIVE;
        return (0);
    } else {
        trunk_table[tid].port[pc].flag |= TRUNK_PORT_ACTIVE;
    }

    rtag = trunk_table[tid].rtag;
    if (trunk_table[tid].active_count == 0) {
        stp_trunk_root_add(stp, tid, lport);
        trunk_table[tid].port[pc].flag |= (TRUNK_PORT_ROOT | TRUNK_PORT_ACTIVE);
        trace(TRACE_TRUNK, TR_VERBOSE,
              "Trunk: added %d(logical, %d phys) to tid %d as root\n",
               lport, port, tid);
                       
    } else {
        stp_trunk_member_add(stp, tid, lport);
        trunk_table[tid].port[pc].flag &= ~TRUNK_PORT_ROOT;
        trunk_table[tid].port[pc].flag |= TRUNK_PORT_ACTIVE;
        trace(TRACE_TRUNK, TR_VERBOSE,
              "Trunk: added %d(logical, %d phys) to tid %d\n", lport, port, tid);
        
    }

    return (0);
}


/* 由于生成树在DOWN状态的时候是不创建生成树端口的
* 因此这里不能够直接返回,因该继续往下查找。
* zhouguis changed this 2005-12-12
 */
/*------------------------------------------------------------------------------
* FUNCTION:stp_trunk_port_add
* DESCRIPTION:添加一个端口到聚合组表。
* AUTHOR:ZHOUGUIS 2005-12-15
-------------------------------------------------------------------------------*/
 
int
stp_trunk_port_add(stp_id_t tree_id, bcm_trunk_t tid, int gport)
{
    spantree_t *stp;
    stp_port_t *stport;
    soc_port_t port;
    int lport,lcport, link_up;
    int unit,pcount;
    /* 如果这时候没有启动STP功能,那么先把它加入到软件表中。 */
    stp = stp_lookup_from_stp_id(tree_id);
    if (stp == NULL) {

        	pcount = trunk_table[tid].port_count;
          if (pcount >= BCM_TRUNK_MAX_PORTCNT) {
              trace(TRACE_TRUNK, TR_ERROR, "Too many ports in trunk\n");
              return (-1);
          }        	
            unit = get_gport_unit(gport);
            lcport = gport_to_lport(gport);
            lport = stp_port_p2l(stp_my_cpuid, unit, lcport);  
            
            trunk_table[tid].port[pcount].num = lport;
            trunk_table[tid].port_count++;
         trunk_table[tid].tree_id = tree_id;   	
            debugk(DK_STP,"add port %d to aggregation %d\n",gport,tid);   	

        return -1;
    }
    /* 如果这时候已经启动STP功能,那么把它加入到软件表中。并且处理STP端口信息。 */

        debugk(DK_STP,"add port %d to aggregation %d\n",gport,tid);
        unit = get_gport_unit(gport);
        lcport = gport_to_lport(gport);
        lport = stp_port_p2l(stp_my_cpuid, unit, lcport);
        pcount = trunk_table[tid].port_count;
        
        if (pcount >= BCM_TRUNK_MAX_PORTCNT) {
            trace(TRACE_TRUNK, TR_ERROR, "Too many ports in trunk\n");
            return (-1);
        }        
        
        trunk_table[tid].port[pcount].num = lport;
        trunk_table[tid].port_count++;
        trunk_table[tid].tree_id = tree_id;           
        stport = stp_port_lookup_from_id(stp, lport);
        if (stport == NULL) {
            link_up = FALSE;
        }
        else{
            link_up = TRUE;
        }
        stp_trunk_add_one_port(stp, tid, lport, link_up);

    return (BCM_E_NONE);
}

/*
 * Function:
 *     stp_trunk_remove_one_port
 * Purpose:
 *     Remove a port from trunk group
 * Parameters:
 *     tid - trunk group id
 *     lport - port number(logical)
 * Returns:
 */
static int
stp_trunk_remove_one_port(spantree_t *stp, bcm_trunk_t tid, int lport)
{
    int i, j, k, pc;
    int need_new_root = 0;

    pc = trunk_table[tid].port_count;
    for (i = 0; i < pc; i++) {
        if (trunk_table[tid].port[i].num == lport) {
            if (trunk_table[tid].port[i].flag & TRUNK_PORT_ROOT) {
                need_new_root = 1;
            }

            /*
             * Tell STP this port is no longer in trunk group
             */
            if (trunk_table[tid].port[i].flag & TRUNK_PORT_ACTIVE) {
                trunk_table[tid].active_count--;
                stp_trunk_member_remove(stp, tid, lport);
            }

            /* remove the port from trunk group */
            for (j = i; j < pc-1; j++) {
                trunk_table[tid].port[j] = trunk_table[tid].port[j+1];
            }
            trunk_table[tid].port_count--;

            /* The removed port used to be the root, select new root */
            if (need_new_root) {
                for (k = 0; k < trunk_table[tid].port_count; k++) {
                    if (trunk_table[tid].port[k].flag & TRUNK_PORT_ACTIVE) {
                        break;
                    }
                }
                stp_trunk_root_add(stp, tid, trunk_table[tid].port[k].num);
                trunk_table[tid].port[k].flag |= TRUNK_PORT_ROOT|TRUNK_PORT_ACTIVE;
                trace(TRACE_TRUNK, TR_LOGIT,
                      "Trunk: change port %d(logical) as root for tid %d\n",
                      trunk_table[tid].port[k].num, tid);
            }

        }
    }

    return (-1);
}

/*
 * Function:
 *     stp_trunk_port_remove
 * Purpose:
 *     Remove ports from trunk group

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -