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

📄 stp_appl.c

📁 stp代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 *     status  - 1:up  0:down
 * Returns:
 */
static void
stp_send_port_info(stp_id_t tree_id, int lport, uint16 type,
                   uint16 status, int porttype)
{
    stp_rdp_data_t *rdpd;
    stp_rdp_port_t *pi;
    int rdp_len;
    int d_cpu;

    /*
     * send new port info to all other modules on the stack
     */
    rdp_len = sizeof(stp_rdp_port_t) + sizeof(stp_rdp_data_t) - 1;

    for (d_cpu = 1; d_cpu <= stp_stk_num_cpu; d_cpu++) {
        if (d_cpu == stp_my_cpuid) {
            continue;
        }

        rdpd = (stp_rdp_data_t *)sal_alloc(rdp_len, "stp");
        rdpd->tree_id = soc_htons(tree_id);
        rdpd->type = soc_htons(STP_RDP_PORT_DATA);
        pi = (stp_rdp_port_t *)rdpd->value;
        pi->lport = soc_htonl(lport);
        pi->info_type = type;
        pi->porttype = porttype;
        pi->status = soc_htons(status);

        rdp_send_async(d_cpu, BCM_RDP_ID_STP, (void *)rdpd, rdp_len,
                       STK_HI_PRIO, stp_rdp_send_callback);
    }

    return;
}

/*
 * Function:
 *     stp_send_bpdu_info
 * Purpose:
 *     Send BPDU to other CPUs in the stack
 * Parameters:
 *     tree_id  - STP instance ID
 *     lport    - port where BPDU is received
 *     bpdu_buf - BPDU packet
 *     bpdu_len - BPDU packet len
 * Returns:
 */
void
stp_send_bpdu_info(stp_id_t tree_id, uint8 *bpdu_buf, int bpdu_len, int lport)
{
    stp_rdp_data_t *rdpd;
    stp_bpdu_info_t *bpdu;
    int rdp_len, d_cpu;

    rdp_len = bpdu_len + sizeof(stp_bpdu_info_t) + sizeof(stp_rdp_data_t) - 2;

    for (d_cpu = 1; d_cpu <= stp_stk_num_cpu; d_cpu++) {
        if (d_cpu == stp_my_cpuid) {
            continue;
        }

        rdpd = (stp_rdp_data_t *)sal_alloc(rdp_len, "stp");
        rdpd->tree_id = soc_htons(tree_id);
        rdpd->type = soc_htons(STP_RDP_BPDU_DATA);
        bpdu = (stp_bpdu_info_t *)rdpd->value;
        bpdu->lport = soc_htonl(lport);
        sal_memcpy(bpdu->bpdu, bpdu_buf, bpdu_len);

        rdp_send_async(d_cpu, BCM_RDP_ID_STP, (void *)rdpd, rdp_len,
                     STK_HI_PRIO, stp_rdp_send_callback);
    }
}

/*
 * Function:
 *     stp_send_timer_info
 * Purpose:
 *     In stack mode, when timer is changed, let all CPU know
 * Parameters:
 *     tree_id - STP instance ID
 *     type    - Hello, max, forward delay etc
 *     value   - New timer
 * Returns:
 *     none
 */
void
stp_send_timer_info(stp_id_t tree_id, uint16 value, uint16 type)
{
    stp_rdp_timer_t *timer_info;
    stp_rdp_data_t *rdpd;
    int rdp_len, d_cpu;

    rdp_len = sizeof(stp_rdp_timer_t) + sizeof(stp_rdp_data_t) - 1;

    /*
     * send timer info to all other modules on the stack
     */
    for (d_cpu = 1; d_cpu <= stp_stk_num_cpu; d_cpu++) {
        if (d_cpu == stp_my_cpuid) {
            continue;
        }

        rdpd = (stp_rdp_data_t *)sal_alloc(rdp_len, "stp");
        rdpd->tree_id = soc_htons(tree_id);
        rdpd->type = soc_htons(STP_RDP_TIMER_DATA);
        timer_info = (stp_rdp_timer_t *)rdpd->value;
        timer_info->type = soc_htons(type);
        timer_info->value = soc_htons(value);

        rdp_send_async(d_cpu, BCM_RDP_ID_STP, (void *)rdpd,
                       rdp_len, STK_HI_PRIO, stp_rdp_send_callback);
    }
}

/*
 * Function:
 *     stp_packet_bpdu_offset
 * Purpose:
 *     decide the BPDU message offset from the start of packet
 * Parameters:
 *     ieee_start - start of ethertype/len field of the packet
 * Returns:
 *     the offset of the BPDU message
 */
int
stp_packet_bpdu_offset(uint8 *ieee_start)
{
    e8022_form_t *e8022_hdr;
    uint16 *eth_type;
    int bpdu_offset = 0;

    eth_type = (uint16 *)ieee_start;
    if (soc_ntohs(*eth_type) >= 0x0600) {  /* ethernet II */
        bpdu_offset = STP_BPDU_ETH_OFFSET;
    } else {   /* 802.2 */
        e8022_hdr = (e8022_form_t *)(ieee_start + 2);

        if (e8022_hdr->dsap == 0xaa && e8022_hdr->ssap == 0xaa) {
            bpdu_offset = STP_BPDU_SNAP_OFFSET;
        } else if (e8022_hdr->dsap == 0xff && e8022_hdr->ssap == 0xff) {
            bpdu_offset = STP_BPDU_RAW_OFFSET;
        } else {
            bpdu_offset = STP_BPDU_802_OFFSET;
        }
    }

    return (bpdu_offset);
}

/*
 * Initialize the STP packet queue
 */
static int
stp_pakq_int(int size)
{
    int total;

    total = sizeof(stp_pkt_t) * size;
    if ((stpQ.pakq = sal_alloc(total, "spantree")) == NULL) {
        return (BCM_E_RESOURCE);
    }

    sal_memset(stpQ.pakq, 0, total);
    stpQ.total = size;
    stpQ.count = 0;
    stpQ.head = 0;
    stpQ.tail = 0;
    stpQ.drop = 0;

    /* Setup the packet thread related stuff */
    if ((stpQ.pkt_sem = sal_sem_create("stp_pak", sal_sem_BINARY, 0)) == NULL) {
        return (BCM_E_RESOURCE);
    }

    stpQ.thread_exit = 0;
    if ((stpQ.pkt_thread = sal_thread_create("stp_pkt", SAL_THREAD_STKSZ*2, 100,
                                  stp_packet_thread, 0)) == SAL_THREAD_ERROR) {
        sal_sem_destroy(stpQ.pkt_sem);
        return (BCM_E_RESOURCE);
    }

    return (0);
}

/*
 * Release the STP packet queue
 */
void
stk_pakq_release(void)
{
    stpQ.thread_exit = 1;
    taskDelay(100);
    stpQ.count = 0;
    stpQ.head = 0;
    stpQ.tail = 0;
    stpQ.drop = 0;
    sal_free(stpQ.pakq);
    stpQ.pakq = NULL;

    /* stpQ.thread_exit = 1; */
    sal_sem_give(stpQ.pkt_sem);

}

/*
 * Function:
 *     stp_process_packet
 * Purpose:
 *     DPC for handling STP packets
 * Parameters:
 *     unit       - SOC unit #
 *     pak        - packet
 *     ieee_start - start of ethertype/len field
 *     size       - length
 *     port       - Source port where packet comes in
 * Returns:
 */
void
stp_process_packet(stp_pkt_t *rx_q)
{
    int stp_bpdu_offset, bpdu_size;
    int tree_id, lport;
    uint8 *pak = rx_q->mac_start;


    lport = stp_port_p2l(stp_my_cpuid, rx_q->unit, rx_q->port);

    /* Get VLAN ID, which for now is also the tree ID */
    tree_id = pak[14] & 0xf;
    tree_id <<= 8;
    tree_id |= pak[15] & 0xff;
    debugk(DK_STP,"rx pk from vlan = %d \n",tree_id);
    /*
     * ieee_start points to the byte right after the VLAN + SL stack tag.
     * Based on the encapsulation the packet is using,
     * get the offset of actuall BPDU portion from ieee_start.
     */
    stp_bpdu_offset = rx_q->ieee_start - pak;
    stp_bpdu_offset += stp_packet_bpdu_offset(rx_q->ieee_start);
    bpdu_size = rx_q->size - stp_bpdu_offset;
    /* process the BPDU message */
    
    stp_handle_bpdu_packet(tree_id, pak + stp_bpdu_offset, lport);

    /* In stack mode, send bpdu to all other modules on the stack */
    if (stp_stack_ready) {
        stp_send_bpdu_info(tree_id, (pak + stp_bpdu_offset), bpdu_size, lport);
    }

    /* release original incoming packet */
    bcm_pmux_free(rx_q->unit, pak);

    return;
}

#define STPQ_NEXT(idx) ((idx + 1) % stpQ.total)
#define STPQ_FULL      (stpQ.count == stpQ.total)
#define STPQ_EMPTY     (stpQ.count == 0)

static void
stp_packet_thread(void *param)
{
    stp_pkt_t *rx_q;
    int spl;

    while (!stpQ.thread_exit) 
    {
        /*
         * Service as many packets as possible.
         */

        while (!STPQ_EMPTY) {
            spl = sal_splhi();
            rx_q = &stpQ.pakq[stpQ.head];
            stpQ.head = STPQ_NEXT(stpQ.head);
            stpQ.count--;
            sal_spl(spl);

            stp_lock_link();
            stp_process_packet(rx_q);
            stp_unlock_link();
        }
    
        sal_sem_take(stpQ.pkt_sem, sal_sem_FOREVER);
    }
/*    debugk(DK_STP,"stp packet thread exit\n");*/
    /* thread dies */
    sal_sem_destroy(stpQ.pkt_sem);
}

/*
 * Function:
 *     stp_sys_recv_pkts
 * Purpose:
 *    Function called to receive BPDU packets
 * Parameters:
 *     unit - SOC unit #
 *     info - information about packet
 *     cookie - not used
 * Returns:
 *     bcmPmuxHandledOwned/bcmPmuxNotHandled
 */
bcm_pmux_t
stp_sys_recv_pkts(int unit, bcm_pmux_rx_t *info, void *cookie)
{
    mac_addr_t bpdu_addr = {0x1, 0x80, 0xc2, 0x00, 0x00, 0x00};
    stp_pkt_t *entry;

    /*
     * Check if packet belongs to STP based on packet DA,
     * {0x1,0x80,0xc2,0x00,0x00,0x00} is the DA used in STP BPDU message
     */
    if (ENET_CMP_MACADDR(info->mac_start, bpdu_addr) == 0) {
    	
        /* queue the packet */
        if (STPQ_FULL) {   /* Queue is full */
            stpQ.drop++;
            return (bcmPmuxHandled);
        } else {
            entry = &stpQ.pakq[stpQ.tail];
            entry->unit = unit;
            entry->port = info->rx_port;
            entry->mac_start = info->mac_start;
            entry->ieee_start = info->ieee_start;
            entry->size = info->rx_len;
            stpQ.count++;
            stpQ.tail = STPQ_NEXT(stpQ.tail);
            sal_sem_give(stpQ.pkt_sem);

            return (bcmPmuxHandledOwned);
        }
    }

    return bcmPmuxNotHandled;
}

/*
 * Function:
 *     stp_bpdu_cos_set
 * Purpose:
 *     Set the CONFIG reg to send BPDU packets on high COS queue
 * Parameters:
 *     unit - SOC unit #
 * Returns:
 */
int
stp_bpdu_cos_set(int unit)
{
    uint32 config_reg;
    uint64 cpu_ctrl;
    int	blk, port;
    int num_cos;

    /*
     * Set up two COS queues
    */
    SOC_IF_ERROR_RETURN(bcm_cosq_config_get(unit, &num_cos));

    if (num_cos == 1) {
        bcm_cosq_init(unit);
        bcm_cosq_config_set(unit, 2);
        bcm_cosq_mapping_set(unit, 7, (bcm_cos_queue_t)1);
    } else {
        bcm_cosq_mapping_set(unit, 7, (bcm_cos_queue_t)(num_cos - 1));
    }

    /* BPDU packets use the highest COS queue */
    if (SOC_IS_STRATA(unit)) {
        SOC_BLOCK_ITER(unit, blk, SOC_BLK_ETHER) {
            port = SOC_BLOCK_PORT(unit, blk);
            SOC_IF_ERROR_RETURN (READ_CONFIGr(unit, port, &config_reg));
            soc_reg_field_set(unit, CONFIGr, &config_reg, CPU_PRIf, num_cos-1);
            SOC_IF_ERROR_RETURN (WRITE_CONFIGr(unit, port, config_reg));
        }
    } if (SOC_IS_XGS_SWITCH(unit)) {
        PBMP_E_ITER(unit, port) {
            SOC_IF_ERROR_RETURN (READ_CPU_CONTROLr(unit, port, &cpu_ctrl));
            soc_reg64_field32_set(
            unit, CPU_CONTROLr, &cpu_ctrl, CPU_PROTOCOL_PRIORITYf, 7);
            SOC_IF_ERROR_RETURN (WRITE_CPU_CONTROLr(unit, port, cpu_ctrl));
        }
    }

    return BCM_E_NONE;
}

/*
 * Given a physical port number, return the port type
 */
stp_porttype_t
stp_get_porttype(int unit, int port)
{
    if (IS_FE_PORT(unit, port)) {
	return STP_PORT_TYPE_FE;
    }
    if (IS_GE_PORT(unit, port)) {
	return STP_PORT_TYPE_GE;
    }
    if (IS_XE_PORT(unit, port)) {
	return STP_PORT_TYPE_10G;	/* should be _XE */
    }
    if (IS_HG_PORT(unit, port)) {
	return STP_PORT_TYPE_10G;
    }
    return STP_PORT_TYPE_FE;
}

/*
 * Function:
 *     stp_link_scan_callback
 * Purpose:
 *     Set up a port scan, called whenever port state changes
 * Parameters:
 *     unit - SOC unit #
 *     port - port whose status changes(physical)
 *     info - new port info
 */
void
stp_link_scan_callback(int unit, int port, bcm_port_info_t *info)
{
    spantree_t *stp;
    stp_port_t *stport;
    stp_id_t tree_id;  /* aka vlan ID */
    pbmp_t pbmp;
    int lport, speed,gport;

    if (bcm_stk_port_is_stack(unit, port)) {
        return;
    }

    FOR_ALL_STP(stp) {
        if (!stp_is_running(stp)) {
            continue;
        }

        /* port belongs to this VLAN ? */
        tree_id = stp->external_id;
        bcm_vlan_port_get(unit, tree_id, &pbmp, NULL);
        if (!PBMP_MEMBER(pbmp, port)) {
            continue;
        }

        lport = stp_port_p2l(stp_my_cpuid, unit, port);

        if (info->linkstatus) {
            trace(TRACE_STP, TR_VERBOSE, "Unit %d Port %d Up\n", unit, port);

            /* get the port speed */
            if (bcm_port_speed_get(unit, port, &speed) < 0) {
                trace(TRACE_STP, TR_ERROR, "bcm_port_speed_get err\n");
                speed = 100;
            }

            if (stp_create_stp_port(&stport, stp, lport, "stp port") < 0) {
                return;
            }
            stport->cpu = stp_my_cpuid;
            stport->unit = unit;
            stport->port = port;
            stport->port_type = stp_get_porttype(unit, port);
            stport->link_flags |= STP_LF_LOCAL;
            /* for port id = pri + port id zhouguis adde 2005-12-22*/
            gport = get_global_port(unit,port);
            stport->port_id |= gport;            
            stp_link_up(stp, stport, speed);

            if (stp_stack_ready) {
                stp_send_port_info(tree_id, lport, STP_PORT_INFO_LINK,
                                   speed, stport->port_type);
            }
        } else {
            trace(TRACE_STP, TR_VERBOSE, "\nUnit %d Port %d down\n", unit, port);
            stp_link_down(stp, lport);
            if (stp_stack_ready) {
                stp_send_port_info(tree_id, lport, STP_PORT_INFO_LINK,
                                   0, stport->port_type);
            }
        }
    }

}

/*
 * Function:
 *     stp_port_add
 * Purpose:
 *     Add all ports with link to spanning tree
 */
void
stp_port_add(spantree_t *stp, int stk_mode)
{
    int link, lport;
    int unit, pport, speed,gport;
    pbmp_t pbmp;

⌨️ 快捷键说明

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