stp_process.c

来自「stp代码」· C语言 代码 · 共 1,383 行 · 第 1/3 页

C
1,383
字号
    }
}

/*
 * Set port state to STP_FORWARDING (8.6.13)
 */
static void
make_blocking(spantree_t *stp, stp_port_t *port)
    	{
    if ((port->state == STP_DISABLED) ||
        (port->state == STP_BLOCKING)) {  /* (8.6.13.3) */
        return;
    }

    if (port->state == STP_FORWARDING || port->state == STP_LEARNING) {
        if (port->change_detection_enabled == True) { /* (8.5.5.10) */
            topology_change_detection(stp); /* (8.6.13.3 a) */
        } /* (8.6.14.2.3) */
    }

    set_port_state(stp, port, STP_BLOCKING); /* (8.6.13.3 b) */
    stop_forward_delay_timer(stp, port); /* (8.6.13.3 c) */

    return;
}

/*
 * Set port to some spanning tree state
 */
static void
set_port_state(spantree_t *stp, stp_port_t *port, stp_portstate_t state)
{
    port->state = state;

    /* Set stp state in the hardware */
    stp_port_state_set(stp, port, state);
}

/*
 * Record that a topology change has been detected so we can notify
 * the root that things have changed (8.6.14)
 */
static void
topology_change_detection(spantree_t *stp)
{
    if (root_bridge(stp)) { /* (8.6.14.3 a) */
        stp->topology_change = True; /* (8.6.14.3 a1)*/
        start_tc_timer(stp); /* (8.6.14.3 a2)*/
    } else if (stp->topology_change_detected == False) { /* (8.6.14.3 b) */
        transmit_tcn(stp); /* (8.6.14.3 b1)*/
        start_tcn_timer(stp); /* (8.6.14.3 b2)*/
    }

    stp->topology_change_detected = True; /* (8.6.14.3 c) */
}

/*
 * Acknowledge that a topology change has been answered (8.6.15).
 */
static void
topology_change_acknowledged(spantree_t *stp)
{
    stp->topology_change_detected = False; /* (8.6.15.3 a) */
    stop_tcn_timer(stp); /* (8.6.15.3 b) */
}

/*
 * Reply to a topology change (8.6.16).
 */
static void
acknowledge_topology_change(spantree_t *stp, stp_port_t *port)
{
    port->tc_acknowledge = True; /* (8.6.16.3 a) */
    transmit_config(stp, port); /* (8.6.16.3 b) */
}

/*
 * Operation of the Protocol, process IEEE config message (8.7.1)
 */
void
received_config_bpdu(spantree_t *stp, stp_port_t *port, Config_bpdu *config)
{
    Boolean root;

    root = root_bridge(stp);

    if (port->state != STP_DISABLED) {
        if (supersedes_port_info(stp, port, config)) {  /* (8.7.1.1) */
            record_config_information(stp, port, config); /* (8.7.1.1 a) */
            configuration_update(stp); /* (8.7.1.1 b) */
            port_state_selection(stp); /* (8.7.1.1 c) */
            if ((!root_bridge(stp)) && root) {  /* (8.7.1.1 d) */
                stop_hello_timer(stp);
                if (stp->topology_change_detected) { /* (8.7.1.1 e) */
                    stop_tc_timer(stp);
                    transmit_tcn(stp); /* (8.6.6.1) */
                    start_tcn_timer(stp);
                    }
                }

            if (port == stp->root_port) {
                record_config_timeout_values(stp, config); /* (8.7.1.1 e) */
                config_bpdu_generation(stp); /* (8.6.4.2 a) */
                if (config->tc_acknowledgment) {  /* (8.7.1.1 g) */
                    topology_change_acknowledged(stp); /* (8.6.15.2) */
            }
            }
        } else if (is_designated_port(stp, port)) {  /* (8.7.1.2) */
            reply(stp, port); /* (8.7.1.2) */
        }
    }
}

/*
 * Handle Topology Change Notification (8.7.2)
 */
void
received_tcn_bpdu(spantree_t *stp, stp_port_t *port, Tcn_bpdu *tcn)
{
    if (port->state != STP_DISABLED) {
        if (is_designated_port(stp, port)) {
            topology_change_detection(stp); /* (8.7.2 a) */
            acknowledge_topology_change(stp, port); /* (8.7.2 b) */
        }
    }
}

/*
 * The hello timer expired, generation another hello (8.7.3).
 */
static void
hello_timer_expiry(spantree_t *stp)
{
    config_bpdu_generation(stp);

    start_hello_timer(stp);
}

/*
 * The message age timer expired (8.7.4)
 */
static void
message_age_timer_expiry(spantree_t *stp, stp_port_t *port)
{
    Boolean root;

    root = root_bridge(stp);

    become_designated_port(stp, port); /* (8.7.4 a) */
    configuration_update(stp); /* (8.7.4 b) */
    port_state_selection(stp); /* (8.7.4 c) */

    if ((root_bridge(stp)) && (!root)) {  /* (8.7.4 d) */
        stp->max_age = stp->bridge_max_age; /* (8.7.4 d1) */
        stp->hello_time = stp->bridge_hello_time;
        stp->forward_delay = stp->bridge_forward_delay;
        topology_change_detection(stp); /* (8.7.4 d2) */
        stop_tcn_timer(stp); /* (8.7.4 d3) */
        config_bpdu_generation(stp); /* (8.7.4 d4) */
        start_hello_timer(stp);
    }
}

/*
 * The forward delay timer expired (8.7.5).
 */
static void
forward_delay_timer_expiry(spantree_t *stp, stp_port_t *port)
{
    if (port->state == STP_LISTENING) {  /* (8.7.5 a) */
        set_port_state(stp, port, STP_LEARNING); /* (8.7.5 a1) */
        start_forward_delay_timer(stp, port); /* (8.7.5 a2) */
    } else if (port->state == STP_LEARNING) { /* (8.7.5 b) */
        set_port_state(stp, port, STP_FORWARDING); /* (8.7.5 b1) */
        if (designated_for_some_port(stp)) { /* (8.7.5 b2) */
            if (port->change_detection_enabled == True) {
                topology_change_detection(stp); /* (8.6.14.2.2) */
            }
        }
    }
}

/*
 * Is this designated bridge for any port ?
 */
static Boolean
designated_for_some_port(spantree_t *stp)
{
    stp_port_t *port;

    FOR_ALL_PORTS_IN_STP(stp, port) {
        if (stp_cmpid(port->designated_bridge, stp->bridge_id, ID_BYTES)) {
            return(True);
        }
    }

    return(False);
}

/*
 * Topology change notification timer expired (8.7.6)
 */
static void
tcn_timer_expiry(spantree_t *stp)
{
    transmit_tcn(stp);    /* (8.7.6 a) */
    start_tcn_timer(stp); /* (8.7.6 b) */
}

/*
 * Topology change timer expired (8.7.7)
 */
static void
tc_timer_expiry(spantree_t *stp)
{
    stp->topology_change_detected = False; /* (8.7.7 a) */
    stp->topology_change = False; /* (8.7.7 b) */
}

/*
 * Hold timer expired (8.7.8)
 */
static void
hold_timer_expiry(spantree_t *stp, stp_port_t *port)
{
    if (port->config_pending) {
        transmit_config(stp, port); /* (8.6.1.2) */
    }
}

/*
 * Management of the Bridge Protocol Entity (8.8)
 */
void
activate_spantree(spantree_t *stp)
{
#if 0
    stp_port_t *port;
#endif

    sal_memcpy(stp->designated_root, stp->bridge_id, ID_BYTES);
    stp->root_path_cost = 0;
    stp->root_port = NULL;
    stp->max_age = stp->bridge_max_age;
    stp->hello_time = stp->bridge_hello_time;
    stp->forward_delay = stp->bridge_forward_delay;
    stp->topology_change_detected = False;
    stp->topology_change = False;

    stop_tcn_timer(stp);
    stop_tc_timer(stp);

#if 0
    FOR_ALL_PORTS_IN_STP(stp, port) {  /* (8.8.1 d) */
        /* We do this on link up and not at this point */
        initialize_port(stp, port);
    }
#endif

    port_state_selection(stp); /* (8.8.1 e) */
    config_bpdu_generation(stp); /* (8.8.1 f) */
    start_hello_timer(stp);

    stp->running = True;
}

/*
 * deactivate a STP instance
 */
void
stp_deactivate_spantree(spantree_t *stp)
{
    stp_port_t *port;

    /* canonical STP deactivation */
    stop_hello_timer(stp);
    stop_tcn_timer(stp);
    stop_tc_timer(stp);
    stp->running = 0; 

    /* cancel all our timers active for all our ports */
    FOR_ALL_PORTS_IN_STP(stp, port) {
        stop_message_age_timer(stp, port);
        stop_forward_delay_timer(stp, port);
        stop_hold_timer(stp, port);

        set_port_state(stp, port, STP_FORWARDING);
    }
}

/*
 * initialize a port in a STP instance for the API (8.8.1)
 */
static void
initialize_port(spantree_t *stp, stp_port_t *port)
{
    become_designated_port(stp, port); /* (8.8.1 d1) */
    set_port_state(stp, port, STP_BLOCKING); /* (8.8.1 d2) */
    port->tc_acknowledge = False; /* (8.8.1 d3) */
    port->config_pending = False; /* (8.8.1 d4) */
    port->change_detection_enabled = True; /* (8.8.1 d8) */
    stop_message_age_timer(stp, port); /* (8.8.1 d5) */
    stop_forward_delay_timer(stp, port); /* (8.8.1 d6) */
    stop_hold_timer(stp, port); /* (8.8.1 d7) */
}

/*
 * enable a port due to a management command (8.8.2)
 */
void
enable_port(spantree_t *stp, stp_port_t *port)
{
    initialize_port(stp, port);
    port_state_selection(stp); /* (8.8.2 g) */
}

/*
 * disable a port due to a management command (8.8.3)
 */
void
disable_port(spantree_t *stp, stp_port_t *port)
{
    Boolean root;

    root = root_bridge(stp);
    become_designated_port(stp, port); /* (8.8.3 a) */
    set_port_state(stp, port, STP_DISABLED); /* (8.8.3 b) */
    port->tc_acknowledge = False; /* (8.8.3 c) */
    port->config_pending = False; /* (8.8.3 d) */
    stop_message_age_timer(stp, port); /* (8.8.3 e) */
    stop_forward_delay_timer(stp, port); /* (8.8.3 f) */
    configuration_update(stp); /* (8.8.3 g) */
    port_state_selection(stp); /* (8.8.3 h) */

    if ((root_bridge(stp)) && (!root)) {  /* (8.8.3 i) */
        stp->max_age = stp->bridge_max_age; /* (8.8.3 i1) */
        stp->hello_time = stp->bridge_hello_time;
        stp->forward_delay = stp->bridge_forward_delay;
        topology_change_detection(stp); /* (8.8.3 i2) */
        stop_tcn_timer(stp); /* (8.8.3 i3) */
        config_bpdu_generation(stp); /* (8.8.3 i4) */
        start_hello_timer(stp);
    }
}

/*
 * change a bridge ID (priority and mac address) (8.8.4)
 */
void
set_bridge_id_api(spantree_t *stp, uint8 *new_bridge_id)
{
    stp_port_t *port;
    Boolean root;

    root = root_bridge(stp);

    FOR_ALL_PORTS_IN_STP(stp, port) {   /* (8.8.4 b) */
        if (is_designated_port(stp, port)) {
	    sal_memcpy(port->designated_bridge, new_bridge_id, ID_BYTES);
        }
    }

    sal_memcpy(stp->bridge_id, new_bridge_id, ID_BYTES);
    configuration_update(stp); /* (8.8.4 d) */
    port_state_selection(stp); /* (8.8.4 e) */

    if ((root_bridge(stp)) && (!root)) {  /* (8.8.4 f) */
        stp->max_age = stp->bridge_max_age; /* (8.8.4 f1) */
        stp->hello_time = stp->bridge_hello_time;
        stp->forward_delay = stp->bridge_forward_delay;
        topology_change_detection(stp); /* (8.8.4 f2) */
        stop_tcn_timer(stp); /* (8.8.4 f3) */
        config_bpdu_generation(stp); /* (8.8.4 f4) */
        start_hello_timer(stp);
    }
}

/*
 * Adjust spanning tree topology after changing priority of a port (8.8.5)
 */
void
set_port_priority(spantree_t *stp, stp_port_t *port, uint16 new_port_id)
{
    if (is_designated_port(stp, port)) {  /* (8.8.5 b) */
        port->designated_port = new_port_id;
    }

    port->port_id = new_port_id; /* (8.8.5 c) */

    if ((stp_cmpid(stp->bridge_id, port->designated_bridge, ID_BYTES) == 0) &&
        (port->port_id < port->designated_port)) {
        become_designated_port(stp, port); /* (8.8.5 d1) */
        port_state_selection(stp); /* (8.8.5 d2) */
    }
}

/*
 * Set path cost for a port (8.8.6)
 */
void
set_path_cost(spantree_t *stp, stp_port_t *port, uint32 path_cost)
{
    port->path_cost = path_cost; /* (8.8.6 a) */
    configuration_update(stp); /* (8.8.6 b) */
    port_state_selection(stp); /* (8.8.6 c) */
}

/*
 * Enable change detection (8.8.7)
 */
void
enable_change_detection(spantree_t *stp, stp_port_t *port)
{
    port->change_detection_enabled = True;
}

/*
 * Enable change detection (8.8.8)
 */
void
disable_change_detection(spantree_t *stp, stp_port_t *port)
{
    port->change_detection_enabled = False;
}

/*
 * pseudo-implementation-specific timer running support
 */
static void
stp_tick(spantree_t *stp)
{
    stp_port_t *port;

    if (hello_timer_expired(stp)) {
        hello_timer_expiry(stp);
    }

    if (tcn_timer_expired(stp)) {
        tcn_timer_expiry(stp);
    }

    if (tc_timer_expired(stp)) {
        tc_timer_expiry(stp);
    }

    FOR_ALL_PORTS_IN_STP(stp, port) {
        if (message_age_timer_expired(stp, port)) {
            message_age_timer_expiry(stp, port);
        }
    }

    FOR_ALL_PORTS_IN_STP(stp, port) {
        if (forward_delay_timer_expired(stp, port)) {
            forward_delay_timer_expiry(stp, port);
        }

        if (hold_timer_expired(stp, port)) {
            hold_timer_expiry(stp, port);
        }
   }
}

⌨️ 快捷键说明

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