天天看點

ONOS中收到OF消息後,分發消息流程分析

首先介紹代碼是如何走到消息處理的 APP ,然後分析分發消息的規則的代碼的結構和文法。

代碼如何走到消息處理的方法

ONOS中收到OF消息後,分發消息流程分析
  • ① OFChannelHandler在Channel狀态WAIT_DESCRIPTION_STAT_REPLY中調用Controller類的getOFSwitchInstance方法來擷取交換機執行個體;
  • ② Controller類的getOFSwitchInstance方法,則調用DriverManager的靜态方法getSwitch來擷取不同廠家實作的交換機執行個體,擷取的原則是基于OFDescStatsReply消息中的“廠家資訊”和“硬體資訊”。注意:在執行個體化交換機之後,将OpenFlowAgent執行個體賦給了該交換機,其中OpenFlowAgent執行個體的産生是在OpenFlowControllerImpl類的内部類OpenFlowSwitchAgent類執行個體化的,見⑤。
  • ③ 這裡的driver意味着對接不同廠家的OF交換機,上圖隻是列出了少數幾種OF交換機,例如:支援OF_13的OVS,OF_10的OVS和光的OF交換機
  • ④ 這裡的OF交換機都繼承了AbstractOpenFlowSwitch的handleMessage方法,而handleMessage方法調用了就是agent的processMessage方法,然後processMessage方法調用了processPacket方法,在processPacket方法中,就是處理消息分發的分發口
  • 分析分發消息的規則的代碼的結構和文法

    分發消息的規則

    • 在 processPacket 方法中:
    • 當收到 OFPortStatus 消息,通知OpenFlowSwitchLister的portChanged方法。
    • 當收到OFFeaturesPeply消息,通知OpenFlowSwitchLister的switchChanged方法。
    • 當收到OFPacketIn消息,通知PacketListener的handlePacket方法。
    • 當收到OFFlowRemoved消息和OFError消息,交給OpenFlowEventListener的handleMessage來處理。
    • 當收到OFBarrierReply消息,交給OpenFlowEventListener的handleMessage來處理。
    • 當收到OFExperimenter消息,僅僅處理experimenter為0x748771的擴充光消息,最後交給交給 OpenFlowSwitchListener 的 portChanged 來處理。
    • 當收到OFStatsReply消息時,根據其消息類型來進行分類處理:
    • 如果類型為PortDesc,通知OpenFlowSwitchLister的switchChanged方法;
    • 如果類型為Flow,首先構造OFFlowStateReply消息,然後調用OpenFlowEventListener的handleMessage來處理這個消息;
    • 如果類型為Group,首先構造 OFGroupStatsReply 消息,然後調用OpenFlowEventListener的handleMessage來處理這個消息;
    • 如果類型為GROUP_DESC,首先構造 OFGroupDescStatsReply 消息,然後調用OpenFlowEventListener的handleMessage來處理這個消息;
    • 如果類型為PORT,直接調用OpenFlowEventListener的handleMessage來處理這個消息。

    代碼結構

    由上面的分發規則,我們可以看出,許多OF消息都交給了不同的listener的不同方法來進行處理,例如OFSwitchListener的portChanged和switchChanged方法,OpenFlowEventListener的handleMessage方法,PacketListener的handlePacket方法等。下面主要分析各個APP如何拿到這些OF消息,并且同一個消息在各個APP之間處理的先後順序是如何定義的。
    ONOS中收到OF消息後,分發消息流程分析
    以 Packet-in 處理為例來說明上面兩個問題,

    South-OF Layer

    控制器收到OFPacketIn的消息後,周遊所有的 ofPacketListener 容器中的 Packetlistener ,調用其中的 handlePacket 方法來處理 Packet-in 消息,
    for (PacketListener p : ofPacketListener.values()) {
        p.handlePacket(pktCtx);
    }
               
    那麼問題來了,ofPacketListener 中的 listener 什麼時候加進來的呢?在 OpenFlowController 接口中提供了 addPacketListener 方法,以便往 ofPacketListener 容器中加入 PacketListener 。

    Provider Layer

    OpenFlowPacketProvider 類的屬性 controller 執行個體化 OpenFlowController,采用 OSGI 的注解方式,來添加對 OpenFlowControllerImpl 的引用
    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected OpenFlowController controller;
               
    然後在 OpenFlowPacketProvider 啟動的時候,将執行個體化的 listener 加入到 ofPacketListener 容器中,這裡需要注意兩點:1. addPacketListener 方法有個優先級, ofPacketListener 的類型是 Multimap

    Core Layer

    在 InternalPacketProviderService 的 processPacket 方法中,周遊 processors 容器中所有的 PacketProcessor 的 process 方法來處理。
    @Override
    public void processPacket(PacketContext context) {
        // TODO filter packets sent to processors based on registrations
        for (PacketProcessor processor : processors.values()) {
            processor.process(context);
        }
    }
               
    這種代碼的結構(紅色部分)類似于 South-OF Layer 到 Provider Layer 的跨層調用結構(紫色部分),這裡将不再贅述。這種代碼的結構最大的好處就是層間解耦。

    App Layer

    在 App Layer 中,提供了兩個 APP 作為例子來說明第二個問題,對于同一個 OF 消息,各個 APP 處理的先後順序,在 addProcessor 方法中,除了添加各個 APP 的 processor 之外,還有另外一個屬性,那就是優先級,用來處理調用順序的問題。在 ProxyArp 這個 APP 中,優先級為 PacketProcessor.ADVISOR_MAX + 1
    packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 1);
               
    在 BGPRouter 這個 APP 中,優先級為 PacketProcessor.ADVISOR_MAX + 4
    packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 4);
               
    優先級越低,越先處理,其原理是利用了 HashMap 的有序性,對于同優先級的 processer ,後加入的 processer 将覆寫前面的 processor 。