标签: ONOS

  • ONOS官方示例应用解析

    onos-app-calendar

    一个RESTful的web应用,提供添加链路时延、带宽限制的Intent。用到了ConnectivityIntent。完成功能的逻辑

        /**
         * Create an Intent for a bidirectional path with constraints.
         *
         * @param key optional intent key
         * @param src the path source (DPID or hostID)
         * @param dst the path destination (DPID or hostID)
         * @param srcPort the source port (-1 if src/dest is a host)
         * @param dstPort the destination port (-1 if src/dest is a host)
         * @param bandwidth the bandwidth (mbps) requirement for the path
         * @param latency the latency (micro sec) requirement for the path
         * @return the appropriate intent
         */
        private Intent createIntent(Key key,
                                    String src,
                                    String dst,
                                    String srcPort,
                                    String dstPort,
                                    Long bandwidth,
                                    Long latency) {
    
            TrafficSelector selector = buildTrafficSelector();
            TrafficTreatment treatment = builder().build();
    
            final Constraint constraintBandwidth =
                    new BandwidthConstraint(Bandwidth.mbps(bandwidth));
            final Constraint constraintLatency =
                    new LatencyConstraint(Duration.of(latency, ChronoUnit.MICROS));
            final List<Constraint> constraints = new LinkedList<>();
    
            constraints.add(constraintBandwidth);
            constraints.add(constraintLatency);
    
            if (srcPort.equals("-1")) {
                HostId srcPoint = HostId.hostId(src);
                HostId dstPoint = HostId.hostId(dst);
                return HostToHostIntent.builder()
                        .appId(appId())
                        .key(key)
                        .one(srcPoint)
                        .two(dstPoint)
                        .selector(selector)
                        .treatment(treatment)
                        .constraints(constraints)
                        .build();
    
            } else {
                ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort));
                ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort));
                return TwoWayP2PIntent.builder()
                        .appId(appId())
                        .key(key)
                        .one(srcPoint)
                        .two(dstPoint)
                        .selector(selector)
                        .treatment(treatment)
                        .constraints(constraints)
                        .build();
            }
        }
    
    
        /**
         * Synchronously submits an intent to the Intent Service.
         *
         * @param intent intent to submit
         * @return true if operation succeed, false otherwise
         */
        private boolean submitIntent(Intent intent)
                throws InterruptedException {
            IntentService service = get(IntentService.class);
    
            CountDownLatch latch = new CountDownLatch(1);
            InternalIntentListener listener = new InternalIntentListener(intent, service, latch);
            service.addListener(listener);
            service.submit(intent);
            log.info("Submitted Calendar App intent and waiting: {}", intent);
            if (latch.await(TIMEOUT, TimeUnit.SECONDS) &&
                    listener.getState() == INSTALLED) {
                return true;
            }
            return false;
        }
    
    

    onos-app-carrierethernet

    根据pom.xml文件的内容,我们可以知道这个应用是用于运营以太网服务(Carrier Ethernet),具体介绍在Carrier Ethernet,由城域以太网论坛(MEF)建立。CE包含五个模块:保护、QoS、扩展、业务管理、TDM。个人理解是,希望以太网上的流量,能够在SDN环境下加入一定的识别特征,这样才能方便城域网中的网络设备根据这些特征进行服务的定制。这个项目相对来说比较复杂,而且更新也非常的频繁,先挖个坑在这里,以后有时间的话可以认真阅读一下其实现。

    onos-app-database-perf

    一个用来测试ONOS集群存储数据性能的应用,在activate中包含有对于StorageService的使用,包括创建并发式Map的方法,注册序列化器KryoNamespace等,之后创建多个线程测试具体的性能指标。

    onos-app-ecord-co

    一个CORD的实现应用,CORD(Central Office Re-architected as a DataCenter),意为在家庭、公司等网络边界的基础网络设备,实现一个数据中心的服务功能。CORD目前有三种类型:ECORD、RCORD和MCORD,具体的详情可以查看CORD。这个应用给出了一个ECORD的实现方案。这个应用比较全面地展示了ONOS的抽象子系统概念,我们可以从项目的结构看出来。

    CentralOffice.java文件是组件的主文件,主要工作是注册应用,并且创建了一个名为BigSwitchDeviceProvider的对象,那么接下来我们去找找实现。BigSwitchDeviceProvider继承于DeviceProvider。从前面两次的loadConfig操作中我们可以看出来这个应用支持修改config文件,并且提供有RPC和RESTful两种修改模式,然而目前我对于ConfigService还没有太深的了解,因此这里填个坑等到以后再来了解。在activate方法中基本就是向deviceProvider中注册了一个设备,接下来使用LLDP协议发现网络拓扑。为了完成LLDP的工作,程序中使用到了onlab-misc中的ONOSLLDP工具类,方便使用LLDP协议。

        @Activate
        public void activate(ComponentContext context) {
            cfgService.registerProperties(getClass()); // 在ComponentConfigService上进行注册
            loadRpcConfig(context); 
            loadRestConfig(context); 
    
            // setup service to, and register with, providers
            try {
                remoteServiceContext = rpcService.get(URI.create(remoteUri));
            } catch (UnsupportedOperationException e) {
                log.warn("Unsupported URI: {}", remoteUri);
            }
            providerId = new ProviderId(schemeProp, idProp);
            executor = newSingleThreadScheduledExecutor(groupedThreads("onos/bigswitch", "discovery-%d"));
            registerToDeviceProvider();
            prepareProbe();
            registerToLinkServices();
    
            // start listening to config changes
            NetworkConfigListener cfglistener = new InternalConfigListener();
            cfgRegistry.addListener(cfglistener);
            cfgRegistry.registerConfigFactory(xcConfigFactory);
            log.info("Started");
        }
    
        @Deactivate
        public void deactivate() {
            packetService.removeProcessor(packetProcessor);
    
    
            // advertise all Links as vanished
            knownLinks.invalidateAll();
    
            cfgRegistry.unregisterConfigFactory(xcConfigFactory);
            cfgService.unregisterProperties(getClass(), false);
            unregisterFromLinkServices();
            executor.shutdownNow();
            unregisterFromDeviceProvider();
            // Won't hurt but necessary?
            deviceProviderService = null;
            providerId = null;
            log.info("Stopped");
        }
    
        @Modified
        public void modified(ComponentContext context) {
            log.info("Reloading config...");
            // Needs re-registration to DeviceProvider
            if (loadRpcConfig(context)) {
                // unregister from Device and Link Providers with old parameters
                unregisterFromLinkServices();
                unregisterFromDeviceProvider();
                // register to Device and Link Providers with new parameters
                try {
                    remoteServiceContext = rpcService.get(URI.create(remoteUri));
                    providerId = new ProviderId(schemeProp, idProp);
                    registerToDeviceProvider();
                    registerToLinkServices();
                } catch (UnsupportedOperationException e) {
                    log.warn("Unsupported URI: {}", remoteUri);
                }
                log.info("Re-registered with Device and Link Providers");
            }
    
            // Needs to advertise cross-connect links
            if (loadRestConfig(context)) {
                advertiseCrossConnectLinksOnAllPorts();
            }
        }
    
    
  • org.onosproject.fwd 应用解析

    ONOS 二层转发应用

    org.onosproject.fwd应用应该说是ONOS中最核心的应用了,要想让我们创建的Mininet虚拟网络实现二层互通,就需要激活这个官方应用,因此从这个应用中我们能够学习到ONOS对网络的抽象方式,以及二层转发功能实现方式。截至本文发布之时ONOS的最新版本是1.13.0-SNAPSHOT,因此这里的源码也截至最新开发版。首先我们还是看一下应用的pom.xml文件。

    <?xml version="1.0" encoding="UTF-8"?>
    <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-apps</artifactId>
            <version>1.13.0-SNAPSHOT</version>
        </parent>
    
        <artifactId>onos-app-fwd</artifactId>
        <packaging>bundle</packaging>
    
        <description>Reactive forwarding application using flow subsystem</description>
    
        <properties>
            <onos.app.name>org.onosproject.fwd</onos.app.name>
            <onos.app.title>Reactive Forwarding App</onos.app.title>
            <onos.app.category>Traffic Steering</onos.app.category>
            <onos.app.url>http://onosproject.org</onos.app.url>
            <onos.app.readme>Reactive forwarding application using flow subsystem.</onos.app.readme>
        </properties>
    
        <dependencies>
            ...
        </dependencies>
    
    </project>
    
    

    根据简介,我们可以得知这里的二层转发方式是使用Flow子系统来实现的,具体细化一下应该是FlowObjectiveService。更加详尽的介绍我们可以在BUCK文件中找到(值得一提的是,ONOS已经使用BUCK作为默认构建方式,虽然Maven仍然可以使用)。

    Provisions traffic between end-stations using hop-by-hop flow programming by intercepting packets for which there are currently no matching flow objectives on the data plane. 
    The paths paved in this manner are short-lived, i.e. they expire a few seconds after the flow on whose behalf they were programmed stops. 
    The application relies on the ONOS path service to compute the shortest paths. 
    In the event of negative topology events (link loss, device disconnect, etc.), the application will proactively invalidate any paths that it had programmed to lead through the resources that are no longer available.
    

    应用结构

    org.onosproject.fwd下包含几个文件

    MacAddressCompleter.java
    ReactiveForwarding.java
    ReactiveForwardingCommand.java
    ReactiveForwardMetrics.java
    

    MacAddressCompleter

    public class MacAddressCompleter implements Completer {
        @Override
        public int complete(String buffer, int cursor, List<String> candidates) {
            // Delegate string completer
            StringsCompleter delegate = new StringsCompleter();
            EventuallyConsistentMap<MacAddress, ReactiveForwardMetrics> macAddress;
            // Fetch our service and feed it's offerings to the string completer
            ReactiveForwarding reactiveForwardingService = AbstractShellCommand.get(ReactiveForwarding.class);
            macAddress = reactiveForwardingService.getMacAddress();
            SortedSet<String> strings = delegate.getStrings();
            for (MacAddress key : macAddress.keySet()) {
                strings.add(key.toString());
            }
            // Now let the completer do the work for figuring out what to offer.
            return delegate.complete(buffer, cursor, candidates);
        }
    }
    

    很容易看出来,这个类是用来CLI下补全MAC地址的,在resources/OSGI-INF.blueprint/shell-config.xml文件中我们可以看到命令的定义方式。

    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
        <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
            <command>
                <action class="org.onosproject.fwd.ReactiveForwardingCommand"/>
                <completers>
                <ref component-id="MacAddressCompleter"/>
                </completers>
            </command>
        </command-bundle>
        <bean id="MacAddressCompleter" class="org.onosproject.fwd.MacAddressCompleter"/>
    </blueprint>
    

    Completer声明为一个bean,引用在org.onosproject.fwd.ReactiveForwardingCommand中。那么我们接下来看一下Command的实现。

    ReactiveForwardingCommand

    @Command(scope = "onos", name = "reactive-fwd-metrics",
            description = "List all the metrics of reactive fwd app based on mac address")
    public class ReactiveForwardingCommand extends AbstractShellCommand {
        @Argument(index = 0, name = "mac", description = "One Mac Address",
                required = false, multiValued = false)
        String mac = null;
        @Override
        protected void execute() {
            ReactiveForwarding reactiveForwardingService = AbstractShellCommand.get(ReactiveForwarding.class);
            MacAddress macAddress = null;
            if (mac != null) {
                macAddress = MacAddress.valueOf(mac);
            }
            reactiveForwardingService.printMetric(macAddress);
        }
    }
    

    可以看到,这里用注解创建了一个CLI命令,名为onos:reactive-fwd-metrics,后面加mac地址,可以打印出对应主机的metrics。

    onos> onos:reactive-fwd-metrics aa:0e:a8:c8:c9:a8
    -----------------------------------------------------------------------------------------
     MACADDRESS 						 Metrics
     AA:0E:A8:C8:C9:A8 			 null
    

    ReactiveForwardMetrics

    public class ReactiveForwardMetrics {
        private Long replyPacket = null;
        private Long inPacket = null;
        private Long droppedPacket = null;
        private Long forwardedPacket = null;
        private MacAddress macAddress;
    }
    

    可以看到,ReactiveForwardMetrics这个应用是用来统计Packet的处理情况的,上面的代码中省略了对数量进行更新的函数以及toString函数。

    ReactiveForwarding

    这个类是fwd应用中最核心的文件,实现了转发的具体逻辑。