SDN开发笔记(七):L2switch源码分析(上)

前言

一般按照odl官方文档或者wiki安装L2switch组件会采用在karaf控制台上输入feature:install odl-l2switch-all命令,该命令是将L2switch组件全部安装到odl控制器,而L2switch组件包括packethandler、loopremover、l2switch-main、hosttracker、arphandler、addresstracker模块这几个,模块之间的相互依赖关系可以在features当中查看。

模块功能介绍

如上所述,L2switch组件包括packethandler、loopremover、l2switch-main、hosttracker、arphandler、addresstracker模块,各个模块先简单描述功能,后面会详细从代码上分析。

1、Packethandler :数据包处理器

Packethandler就是将openflowplugin接收到的packetin数据包解封装送到其他模块,并且按照顺序发送,是L2switch与openflowplugin的桥梁,所有的需要l2switch处理的packetin报文都会经过它处理解析,所以分析l2switch需要先从Packethandler分析。

Packethandler模块的入口在PacketHandlerModule.java的createInstance函数:

此函数当中调用了initiateDecoders函数进行初始化,其实也就是new出一些解码器对象,比如EthernetDecoder、ArpDecoder、Ipv4Decoder、Ipv6Decoder解码器。

解码器的设计是先定义一个抽象类,这样一来其他解码器只要继承该抽象类,然后做自己的具体实现就可以了。所以各个文件描述如下:

AbstractPacketDecoder.java——定义的抽象类,所有解封装器必须继承实现其中的方法。

EthernetDecoder.java——mac帧解码器类,openflowplugin接收到的报文上送至控制器,由EthernetDecoder统一mac帧解包(去掉mac帧头),再发送给对应的解码类(ARP、IPV4、IPV6)处理(此过程并不是先判断是arp还是ip报文再发送,而是发送广播notification,所有解码器都能接受到该广播,只不过解码器当中自己去判断是否是自己应该解的报文——canDecode,如果不是则不处理)。

先看EthernetDecoder以太网mac帧的解码,首先EthernetDecoder是实现PacketProcessingListener接口,当openflowplugin接收到packetIn报文时,就会发出notification出来,此时PacketProcessingListener的onPacketReceived函数就会被调用,所以所有packetIn报文都会通过onPacketReceived函数进行后续处理。

报文进入decodeAndPublish之后转到AbstractPacketDecoder抽象类当中,

然后进入decode函数,此函数是抽象函数,所以由具体类实现,比如刚刚是EthernetDecoder转进来的报文,则由EthernetDecoder解析。

解析完了之后,继续采用notification的方式发布,这样报文就经过了mac帧的解码,继续流向下一个环节。

再看IPV4解码类,注意到刚刚EthernetDecoder将报文解码之后,发出notification,而Ipv4Decoder实现了EthernetPacketListener,所以Ipv4Decoder能够收到上述通告,进入onEthernetPacketReceived函数

同理Ipv4Decoder也会跟EthernetDecoder将报文内容解析出来,并将报文以notification形式发出去。

整个Packethandler的报文处理就是这样,所以如果我们想自己定义一种新的packetin报文上送到控制器,就可以在此处按照这样的流程进行报文解析,比如思科自己的cdp报文解析。

最后归类下:

EthernetDecoder.java – 以太网帧解码类

ArpDecoder.java – arp报文解码类

Ipv4Decoder.java -- IPV4报文解码类

Ipv6Decoder.java --IPV6报文解码类

2、Addresstracker

由openflowplugin发上来的报文经过Packethandler处理之后,就会经过Addresstracker模块进行网络设备的MAC地址以及IP学习。

Addresstracker的入口在AddressTrackerModule.java文件当中的函数createInstance。

稍微解释下,AddressObservationWriter是一个公有类,在56-addresstracker.xml当中配置了observe-addresses-from节点,可以是arp、ipv4、ipv6,默认是arp,是arp则调用AddressObserverUsingArp监听arp报文,然后调用addressObservationWriter的addAddress函数添加地址(mac-ip)到md-sal的Inventory,从而触发Hosttracker的主机发现。如果发现地址是已经存在的,则通过timestampUpdateInterval来判断是否需要更新地址时间戳。

比如根据arp来学习设备地址,则进入AddressObserverUsingArp.java文件,可以看到该文件对可以监听上述的Packethandler通告,这样arp报文就流入此文件进行处理。

接收arp报文通告之后,可以根据报文的源mac、源IP等加入datastore。

进入addressObservationWriter.addAddress()函数就是MAC的学习,一般来说是主机host的MAC学习,为下面的hosttracker提供数据。

学习到了MAC之后,将该mac信息以AddressCapableNodeConnector通过Augmentation的方式merge到NodeConnector数据节点,也就是在address-tracker.yang中定义的数据节点,此时merge的数据是在inventory数据库当中。

3、Hosttracker 主机发现

随着上述的流程,当学习到主机host的mac之后,Hosttracker会将新主机以node的形式添加到network-topology当中,这样web前端就有主机节点显示出来。

Hosttracker入口在HostTrackerModule.java的createInstance函数当中,从该函数当中new出一个HostTrackerImpl对象,并注册数据监听器,主要是监听上述的NodeConnector 的AddressCapableNodeConnector数据变化。

当Addresstracker学习到主机mac之后,merge主机的AddressCapableNodeConnector到NodeConnector就会引起hostracker进入onDataChanged函数。

从而进入packetReceived函数,进而进入processHost函数。

在processHost函数当中就将主机添加到network-topology数据节点当中,并建立主机与交换机的link链接。

private void processHost(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node,
            NodeConnector nodeConnector,
            Addresses addrs) {
        List<Host> hostsToMod = new ArrayList<>();
        List<Host> hostsToRem = new ArrayList<>();
        List<Link> linksToRem = new ArrayList<>();
        List<Link> linksToAdd = new ArrayList<>();
        synchronized (hosts) {
            log.trace("Processing nodeConnector " + nodeConnector.getId().toString());
            HostId hId = Host.createHostId(addrs);
            if (hId != null) {
                if (isNodeConnectorInternal(nodeConnector)) {
                    log.trace("NodeConnector is internal " + nodeConnector.getId().toString());
                    removeNodeConnectorFromHost(hostsToMod, hostsToRem, nodeConnector);
                    hosts.removeAll(hostsToRem);
                    hosts.putAll(hostsToMod);
                } else {
                    log.trace("NodeConnector is NOT internal " + nodeConnector.getId().toString());
                    //新建主机节点
                    Host host = new Host(addrs, nodeConnector);
                    if (hosts.containsKey(host.getId())) {
                        hosts.get(host.getId()).mergeHostWith(host);
                    } else {
                        hosts.put(host.getId(), host);
                    }
                   //创建主机与交换机的连接
                    List<Link> newLinks = hosts.get(host.getId()).createLinks(node);
                    if (newLinks != null) {
                        linksToAdd.addAll(newLinks);
                    }
                    //保存主机节点信息
                    hosts.submit(host.getId());
                }
            }
        }
        //保存link信息
        writeDatatoMDSAL(linksToAdd, linksToRem);
}

在hosttracker当中实现主机发现功能,只有主机主动发出报文并经过openflow交换机以packetin形式上送控制器,该报文经过packethandler处理,再到addresstracker,最后由hosttracker写入数据库,该主机节点才能显示到web的拓扑上,因此当我们采用mininet模拟一个哑铃式网络,启动网络是在web的拓扑上只能看到两台交换机,并未出现主机节点,只有pingall之后才能出现主机节点。

由于篇幅有限,下篇继续分析Loopremover、Arphandler等模块。

原文发布于微信公众号 - SDNLAB(SDNLAB)

原文发表时间:2016-12-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Golang构建HTTP服务(二)--- Handler,ServeMux与中间件

Golang标准库http包提供了基础的http服务,这个服务又基于Handler接口和ServeMux结构的做Mutilpexer。实际上,go的作者设计Ha...

42830
来自专栏Android开发实战

Nuwa学习笔记

With this Nuwa project,you can also have the repairing power, fix your android a...

13420
来自专栏Golang语言社区

Golang语言社区--go语言编写Web程序

首先,要有一个Linux, OS X, or FreeBSD系统,可以运行go程序。如果没有的话,可以安装一个虚拟机(如VirtualBox)或者 Virtua...

99870
来自专栏微服务那些事儿

java多线程(一)快速认识线程

答:继承Thread类,实现Runnable接口,为了展示自己学识的渊博,还可能还会说实现Callable接口通过FutureTask包装器来创建Thread线...

16140
来自专栏IT技术精选文摘

Java并发入门指南

关于Java并发 从创建起,Java已经支持核心的并发概念,如线程和锁。本指南帮助Java开发人员使用多线程程序来了解核心并发概念以及如何应用它们。本指南涵盖...

22790
来自专栏友弟技术工作室

beego路由配置路由设置

web框架中,路由是重要的一环,对于beego的路由配置如何? 让我们从入口文件先分析起来吧:

55310
来自专栏无题

线程安全与锁优化——深入理解JVM阅读笔记

我根据我的理解把一些关键的要点整理了出来,并对其中一些内容作了删改。 参考地址:http://www.cnblogs.com/pacoson/p/5351355...

36350
来自专栏技术博客

Asp.Net Web API 2第七课——Web API异常处理

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.h...

9430
来自专栏SDNLAB

ODL源码分析之flowmod下发流程

上一篇简单分析了openflowjava到openflowplugin(介绍的hello消息),本篇介绍如何从openflowplugin到openflowja...

31570
来自专栏xingoo, 一个梦想做发明家的程序员

wisock寻址

winsock第一个版本使用sockaddr来强迫使用特定的寻址方式,这样添加其他的协议就不可能了 1 struct sockaddr 2 { 3 u_...

19680

扫码关注云+社区

领取腾讯云代金券