您的位置:

详解OSPF状态机

一、OSPF简介

OSPF(Open Shortest Path First)是一种基于链路状态的路由协议,常见于企业级网络中。它通过在整个网络中分发和计算链路状态信息来构建当前最短路径树。OSPF支持基于IPv4和IPv6的网络,同时可以对不同类型的网络进行分层管理。

二、OSPF状态机介绍

OSPF路由器的工作状态可以根据不同的条件发生变化。状态机是用来描述和维护OSPF路由器工作状态变化的一种方法。

在OSPF中,每个邻居路由器都有一个独特的标识符。状态机会针对每个邻居路由器分别维护一组状态。OSPF状态机主要包括以下四种状态:

  • Down状态:在Down状态下,路由器没有和邻居路由器建立邻居关系。
  • Init状态:在Init状态下,路由器正在尝试和邻居路由器建立邻居关系。
  • Two-way状态:在Two-way状态下,路由器和邻居路由器已经建立了邻居关系并且可以互相通信。
  • Full状态:在Full状态下,路由器和邻居路由器拥有完整的邻居关系,可以在路由表中交换完整的路由信息。

三、状态机过程

1. 邻居路由器发现

在OSPF中,路由器通过多播方式向网络中的所有路由器发送Hello报文。当两个路由器收到对方发送的Hello报文,就会建立邻居关系。

void ospf_rx_hello(ospf_packet* pkt, interface_t* iface){
    //检查收到的报文是否是Hello广播报文
    if(!pkt->header->lsp_type == OSPF_LSP_TYPE_HELLO){
        return;
    }
    
    //从报文中提取邻居路由器信息
    neighbor_info_t neighbor_info;
    neighbor_info.router_id = pkt->header->router_id;
    neighbor_info.ip_address = ntohl(pkt->hello->neighbor_ip);
    
    //根据提供的邻居信息更新状态机中对应路由器的状态
    neighbor_t* neighbor = ospf_add_neighbor(iface->ospf_if, neighbor_info);
    if(neighbor){
        switch(neighbor->state){
            case OSPF_NEIGHBOR_STATE_DOWN:
                ospf_neighbor_event(neighbor, OSPF_NEIGHBOR_EVENT_HELLO_RECEIVED);
                break;
            case OSPF_NEIGHBOR_STATE_INIT:
                ospf_neighbor_event(neighbor, OSPF_NEIGHBOR_EVENT_HELLO_RECEIVED);
                ospf_neighbor_event(neighbor, OSPF_NEIGHBOR_EVENT_TWO_WAY_RECEIVED);
                break;
            case OSPF_NEIGHBOR_STATE_TWO_WAY:
                ospf_neighbor_event(neighbor, OSPF_NEIGHBOR_EVENT_HELLO_RECEIVED);
                ospf_neighbor_event(neighbor, OSPF_NEIGHBOR_EVENT_TWO_WAY_RECEIVED);
                ospf_neighbor_event(neighbor, OSPF_NEIGHBOR_EVENT_ADJ_EXSTART_RECEIVED);
                break;
            case OSPF_NEIGHBOR_STATE_EXSTART:
            case OSPF_NEIGHBOR_STATE_EXCHANGE:
            case OSPF_NEIGHBOR_STATE_LOADING:
            case OSPF_NEIGHBOR_STATE_FULL:
            default:
                break;
        }
    }
}

2. 邻居状态变更

在OSPF中,邻居状态发生变化可能是由于不同事件触发的。比如,当一方路由器收到另一方路由器的Database Descriptor报文时,就会触发邻居状态从Exchange状态转换为Loading状态。同样地,邻居状态也有可能由于链接失效而发生变化,此时状态机会判断邻居路由器是否已经失去连接,并触发状态转换事件。

void ospf_neighbor_state_machine(neighbor_t* neighbor, ospf_neighbor_event_t event){
    switch(neighbor->state){
        case OSPF_NEIGHBOR_STATE_DOWN:
            if(event == OSPF_NEIGHBOR_EVENT_HELLO_RECEIVED){
                neighbor->state = OSPF_NEIGHBOR_STATE_INIT;
            }
            break;
        case OSPF_NEIGHBOR_STATE_INIT:
            if(event == OSPF_NEIGHBOR_EVENT_HELLO_RECEIVED){
                neighbor->state = OSPF_NEIGHBOR_STATE_TWO_WAY;
            }
            break;
        case OSPF_NEIGHBOR_STATE_TWO_WAY:
            if(event == OSPF_NEIGHBOR_EVENT_TWO_WAY_RECEIVED){
                neighbor->state = OSPF_NEIGHBOR_STATE_TWO_WAY;
            } else if(event == OSPF_NEIGHBOR_EVENT_ADJ_EXSTART_RECEIVED){
                neighbor->state = OSPF_NEIGHBOR_STATE_EXSTART;
                ospf_adj_state_machine(neighbor, event);
            }
            break;
        case OSPF_NEIGHBOR_STATE_EXSTART:
            //...
            break;
        case OSPF_NEIGHBOR_STATE_EXCHANGE:
            //...
            break;
        case OSPF_NEIGHBOR_STATE_LOADING:
            //...
            break;
        case OSPF_NEIGHBOR_STATE_FULL:
            //...
            break;
    }
}

3. 邻居关系建立

在OSPF中,当一个路由器和邻居路由器建立完整的邻居关系后,可以在路由表中交换完整的路由信息。

void ospf_rx_dbd(ospf_packet* pkt, neighbor_t* neighbor, interface_t* iface){
    //检查收到的报文是否是Database Descriptor报文
    if(!pkt->header->lsp_type == OSPF_LSP_TYPE_DBD){
        return;
    }
    
    //处理Database Descriptor报文
    ospf_adj_state_machine(neighbor, OSPF_NEIGHBOR_EVENT_ADJ_EXCHANGE);
    
    //检查邻居路由器的状态,决定是否可以开始交换LSA信息
    switch(neighbor->state){
        case OSPF_NEIGHBOR_STATE_EXCHANGE:
            if(ospf_is_exchange_done(neighbor)){
                ospf_adj_state_machine(neighbor, OSPF_NEIGHBOR_EVENT_ADJ_EXCHANGE_DONE);
            }
            break;
        case OSPF_NEIGHBOR_STATE_LOADING:
            //...
            break;
        case OSPF_NEIGHBOR_STATE_FULL:
            if(ospf_is_exchange_done(neighbor)){
                ospf_adj_state_machine(neighbor, OSPF_NEIGHBOR_EVENT_ADJ_EXCHANGE_DONE);
                ospf_send_ls_upd(neighbor, iface);
            }
            break;
        default:
            break;
    }
}

四、总结

OSPF是一种分布式的链路状态路由协议,具有高度的自适应性和可扩展性。OSPF路由器之间的邻居关系是通过状态机进行维护和改变的。状态机确定了路由器之间不同状态的转换条件和事件。状态机的实现需要依据实际情况进行调整和修改。