前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SDN开发笔记(七):L2switch源码分析(上)

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

作者头像
SDNLAB
发布2018-03-30 15:11:23
9020
发布2018-03-30 15:11:23
举报
文章被收录于专栏:SDNLABSDNLAB

前言

一般按照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链接。

代码语言:javascript
复制
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等模块。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SDNLAB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档