ONOS-ifwd-app源码分析总结

2023-05-16

ONOS-ifwd源码分析,参考资料:https://www.sdnlab.com/10297.html
在之前的文章中,介绍了ONOS-sample-apps的获取,但是将其生成的oar文件导入到ONOS-2.0及其以上版本的时候,是不能够运行的,本文在参考了一些资料的基础上,解决ifwd模块对ONOS版本的不兼容问题,并且对ifwd的源码进行分析学习。

1.源码的修改

1.将import里面的apache服务修改成osgi组件,如下

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;

将以上代码修改为

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;

2.修改Reference服务的关键字参数,将

 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected TopologyService topologyService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected PacketService packetService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected HostService hostService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected DeviceService deviceService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected FlowRuleService flowRuleService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected StatisticStore statisticStore;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected FlowObjectiveService flowObjectiveService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected CoreService coreService;

修改为:


    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected CoreService coreService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected TopologyService topologyService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected PacketService packetService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected IntentService intentService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected HostService hostService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected FlowRuleService flowRuleService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected FlowObjectiveService flowObjectiveService;

2.POM文件的修改

由于ifwd模块在拉取下来的时候,pom文件的onos版本是1.8.0版本的,以及依赖也有一些缺失。可以直接粘贴复制我修改后的pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright 2014-2016 Open Networking Foundation
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.onosproject</groupId>
        <artifactId>onos-dependencies</artifactId>
        <version>1.8.0</version>
        <relativePath/><!-- parent is remote -->
    </parent>

    <artifactId>onos-app-ifwd</artifactId>
    <version>1.8.0-SNAPSHOT</version>
    <packaging>bundle</packaging>

    <description>Reactive forwarding application using intent service (experimental)</description>

    <properties>
        <onos.version>2.0.0</onos.version>
        <onos.app.name>org.onosproject.ifwd</onos.app.name>
        <onos.app.origin>ON.Lab</onos.app.origin>
        <onos.app.title>Reactive Forwarding App (Intent)</onos.app.title>
        <onos.app.category>Traffic Steering</onos.app.category>
        <onos.app.url>http://onosproject.org</onos.app.url>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.onosproject</groupId>
            <artifactId>onos-api</artifactId>
            <version>${onos.version}</version>
        </dependency>

        <dependency>
            <groupId>org.onosproject</groupId>
            <artifactId>onos-core-common</artifactId>
            <version>${parent.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.scr.annotations</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
     
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-scr-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.onosproject</groupId>
                <artifactId>onos-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.ifwd模块的运行测试

在IDEA执行mvn clean compile,mvn install,然后在ONOS-WEB-UI界面上将对应的oar模块导入,启动openflow模块,然后启动Mininet进行连通性测试。
在这里插入图片描述在这里插入图片描述在这里插入图片描述

4.ifwd源码分析

1.Karaf技术相关解析:由于ONOS控制器是使用Karaf技术的,而在ifwd模块中,会使用到Karaf加载模块。下面对源码中Karaf组件加载的关键字进行说明。

Component(immediate = true) – 声明一个类作为组件激活,并且强制立即激活
Activate – 标记一个方法作为组件启动时调用
Deactivate – 标记一个方法作为组件关闭时调用
Reference(Cardinality = ReferenceCardinality.MANDATORY_UNARY) – 标记一个服务作为一个应用程序的依赖,并且在该应用程序启动之前,需要这样服务的一个实例被提前加载。

更多信息:http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html。

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected CoreService coreService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected TopologyService topologyService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected PacketService packetService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected IntentService intentService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected HostService hostService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected FlowRuleService flowRuleService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected FlowObjectiveService flowObjectiveService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected PortStatisticsService portStatisticsService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected LinkService linkService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected DeviceService deviceService;

对于上面的源码,翻译过来就是在运作ifwd的其他代码的时候,Karaf会先激活并且调用ONOS的核心服务,拓扑服务,包服务,意图网络服务,主机服务,流表规则服务,流对象服务,端口服务,链路服务,设备服务。

private ApplicationId appId;

由于应用程序在使用ONOS提供服务的时候,都需要有一个application ID,因此要定义一个appId,后面注册的时候使用。

private ReactivePacketProcessor processor = new ReactivePacketProcessor();

这里新建了一个包处理对象,用于后面对接受报文的处理。

private static final int DROP_RULE_TIMEOUT = 300;

private static final EnumSet<IntentState> WITHDRAWN_STATES = EnumSet.of(IntentState.WITHDRAWN,
                                                                            IntentState.WITHDRAWING,
                                                                            IntentState.WITHDRAW_REQ);

这里定义了流表的持续时间,以及一个枚举,用于说明IntenState的状态
IntentState:表示一个意图在其生命周期当中可能达到的状态
IntentState.WITHDRAWN:表示这个意图成功被撤回
IntentState.WITHDRAWING:表示这个意图正在被撤回
IntentState.WITHDRAW_REQ:表示一个应用程序请求撤回一个意图

    @Activate
    public void activate() {
        appId = coreService.registerApplication("org.onosproject.ifwd");

        packetService.addProcessor(processor, PacketProcessor.director(2));

        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        selector.matchEthType(Ethernet.TYPE_IPV4);
        packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);

        log.info("Started");
    }

标记该代码块在组件启动时要先调用,向核心服务注册一个ApplicationId,决定包处理器的优先级,新建一个流选择处理器,并且指定处理的包的IP类型为IPV4。最后是调用packetService.requestPackets方法,输出对应的参数。
这样子,在该模块启动的时候,当接受到包的时候,就能够根据我们设定好的方法进行报文的处理。

    @Deactivate
    public void deactivate() {
        packetService.removeProcessor(processor);
        processor = null;
        log.info("Stopped");
    }

标记该代码块在该组件关闭的时候调同。主要完成的工作是将包处理器移除并且置空。

    private class ReactivePacketProcessor implements PacketProcessor {

        @Override
        public void process(PacketContext context) {
            // Stop processing if the packet has been handled, since we
            // can't do any more to it.
            if (context.isHandled()) {
                return;
            }
            InboundPacket pkt = context.inPacket();
            Ethernet ethPkt = pkt.parsed();

            if (ethPkt == null) {
                return;
            }

            HostId srcId = HostId.hostId(ethPkt.getSourceMAC());
            HostId dstId = HostId.hostId(ethPkt.getDestinationMAC());

            // Do we know who this is for? If not, flood and bail.
            Host dst = hostService.getHost(dstId);
            if (dst == null) {
                flood(context);
                return;
            }

            // Otherwise forward and be done with it.
            setUpConnectivity(context, srcId, dstId);
            forwardPacketToDst(context, dst);


        }
    }

在该代码块,对包处理器进行覆写,以定义我们想要的包转发行为。
一、定义处理方法,需要输入数据包作为参数:
1.判断该包是否已经被处理,若已被处理,则返回
2.将正在处理的入站数据包传递给pkt
3.用以太类型的ethPkt接收入站数据包的解析类型
4.如果该包的解析类型为空,则返回
5.获取该包的源MAC地址,目的MAC地址
6.根据目的MAC地址,在拓扑上精准确定目的主机,若目的主机为空,则调用flood方法,对包进行洪泛
7.目的主机不为空,调用setUpConnectivity方法,在目的节点与源节点之间建立连接
8.调用forwardPacketToDst方法,对包进行转发

    private void flood(PacketContext context) {
        if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
                                             context.inPacket().receivedFrom())) {
            packetOut(context, PortNumber.FLOOD);
        } else {
            context.block();
        }
    }

    // Sends a packet out the specified port.
    private void packetOut(PacketContext context, PortNumber portNumber) {
        context.treatmentBuilder().setOutput(portNumber);
        context.send();
    }

下面对flood方法及其需要用到的方法packetOut进行学习分析
flood方法,需要输入的参数是PacketContext
1.判断设备上的端口是否为收到该包的端口,如果不是的话,调用packetOut方法
2.若设备上的端口是收到该包的端口,阻塞该端口
packetOut方法,需要输入的参数是PacketContext,PortNumber
1.新建一个流量处理生成器,再输入对应的端口参数
2.发送该包

setUpConnectivity利用了ONOS-intent-framework,具体的学习分析以及心得在后面跟大家分享。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ONOS-ifwd-app源码分析总结 的相关文章

随机推荐