1、简介
图1
大家好,上一篇文章已经分析了ODL控制器中LLDP帧的产生及发送;如上图1,LLDP帧通过packet-out消息发给交换机1,交换机1直接将其转发给交换机2,LLDP帧进入交换机2后匹配默认流表(如下图2),然后通过packet-in消息发给控制器。控制器收到LLDP帧之后,会发出notification,通知相应模块进行链路检测处理,这些也是本篇文章将要详细分析的内容。
图2
2、相关Yang模型介绍
通知 Notification是ODL控制器中一种重要的通信机制,它将ODL中不同模块联系起来,使其可以协同工作来完成网络管理功能。本文介绍的链路检测模块多处涉及到注册和发送notification通知,为方便大家理解,先在此处对相关notification以及其所在yang模型做简单介绍。
2-1 packet-processing.yang
packet-processing.yang在ODL项目中的位置:
openflowplugin/model/model-flow-service/src/main/yang/packet-processing.yang
packet-processing.yang源码查看链接:
https://github.com/opendaylight/openflowplugin/blob/8063199feec22ab6a6afa3f102630bae2876ef7d/model/model-flow-service/src/main/yang/packet-processing.yang
在链路检测中模块注册了packet-processing.yang中的通知notification packet-received,即当控制器收到LLDP帧时,就会发送notification通知链路检测模块,表示已经收到LLDP帧,并且把LLDP帧通过notification通知传给链路检测模块。notification packet-received源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
notification packet-received { description "Delivery of incoming packet wrapped in openflow structure."; leaf connection-cookie { type connection-cookie; } leaf flow-cookie { type flow-type:flow-cookie; } leaf table-id { type table-type:table-id; } leaf packet-in-reason { type identityref { base packet-in-reason; } } container match { uses match-type:match; } uses raw-packet; } |
2-2 flow-topology-discovery.yang
flow-topology-discovery.yang在ODL项目中的位置:openflowplugin/model/model-flow-service/src/main/yang/flow-topology-discovery.yang
flow-topology-discovery.yang源码查看链接:https://github.com/opendaylight/openflowplugin/blob/master/model/model-flow-service/src/main/yang/flow-topology-discovery.yang
在链路检测模块中,当发现新的链路后,会主动发出通知notification link-discovere,通知其他相关模块新发现的链路信息。notification link-discovere源码如下:
1 2 3 4 |
notification link-discovered { status deprecated; uses link; } |
在链路老化检测中,当发现链路老化后会立即删除,并同时发送通知notification link-removed,通知其他相关模块链路老化且删除,notification link-removed源码如下:
1 2 3 4 |
notification link-removed { status deprecated; uses link; } |
3、链路发现和老化检测
ODL中链路发现和老化检测模块主要在ODL子项目openflowplugin中,具体位置为:openflowplugin/applications/topology-lldp-discovery,其源码目录如下图3:
图3
该模块主要分两个功能:
- 注册通知notification packet-received,当控制器收到LLDP帧时,会主动发送通知,本模块收到通知后,从LLDP帧中检测链路信息,发布链路发现通知notification link-discovered,并且存入本地哈希表linkToDate中,哈希表linkToDate的键为link对象,值为link老化时间。
- 周期性遍历本地哈希表linkToDate,对链路进行老化检测,若链路老化,则将其从哈希表linkToDate中删除,同时发送通知notification link-removed。
3-1 链路发现检测
链路发现检测的主要代码逻辑在文件LLDPDiscoveryListener.java中,首先类LLDPDiscoveryListener实现了接口PacketProcessingListener,表明注册通知notification packet-received。然后在函数onPacketReceived中,实现链路检测,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
public void onPacketReceived(PacketReceived lldp) { NodeConnectorRef src = LLDPDiscoveryUtils.lldpToNodeConnectorRef(lldp.getPayload(), true); if(src != null) { LinkDiscoveredBuilder ldb = new LinkDiscoveredBuilder(); ldb.setDestination(lldp.getIngress()); ldb.setSource(new NodeConnectorRef(src)); LinkDiscovered ld = ldb.build(); notificationService.publish(ld); lldpLinkAger.put(ld); } } |
代码分析:函数参数PacketReceived lldp,即为控制器收到的LLDP帧。首先从LLDP帧中提取link的目的port和源port,检测出link信息,然后调用函数publish,发布link发现通知,并且将link存入本地哈希表linkToDate。
存入本地哈希表源码如下:
1 2 3 4 5 |
public void put(LinkDiscovered link) { Date expires = new Date(); expires.setTime(expires.getTime() + linkExpirationTime); linkToDate.put(link, expires); } |
此处有一点需要注意,在将link信息存入本地哈希表linkToDate时,若link不是首次发现,代码中会同时更新link对应的老化时间。这样只要link正常,可转发LLDP帧,就能不断更新其老化时间,从而在老化检测中不被删除;而当link故障不能通过LLDP帧时,其对应老化时间将不再更新,则会在老化检测中发现,进而删除,这就是ODL中维护链路及时更新的机制。
3-2 链路老化检测
链路老化检测的主要代码逻辑在文件LLDPLinkAger.java中,此代码中使用类Timer实现周期性老化检测操作,其构造函数如下:
1 2 3 4 5 6 |
public LLDPLinkAger(final long lldpInterval, final long linkExpirationTime) { this.linkExpirationTime = linkExpirationTime; linkToDate = new ConcurrentHashMap<>(); timer = new Timer(); timer.schedule(new LLDPAgingTask(), 0, lldpInterval); } |
其中linkExpirationTime表示link从发现到老化的有效时间;linkToDate是存储link信息和link老化时间的哈希表;timer.schedule(new LLDPAgingTask(), 0, lldpInterval)表示周期性执行link老化检测操作。其中link老化检测逻辑代码在类LLDPAgingTask中定义。源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private class LLDPAgingTask extends TimerTask { @Override public void run() { for (Entry<LinkDiscovered,Date> entry : linkToDate.entrySet()) { LinkDiscovered link = entry.getKey(); Date expires = entry.getValue(); Date now = new Date(); if(now.after(expires)) { if (notificationService != null) { LinkRemovedBuilder lrb = new LinkRemovedBuilder(link); notificationService.publish(lrb.build()); linkToDate.remove(link); } } } |
代码分析:通过Date now = new Date()获得系统当前时间,并且遍历哈希表linkToDate,和每个link的老化时间比较,检测此link是否已经老化,如果已经老化,则发布通知notification link-removed,并且将link从哈希表中删除。
3-3 在datastore中写入和删除链路操作
由上文可知,当检测到新链路时,会发出通知notification link-discovere;当检测到链路老化时,删除链路时,也会发出通知notification link-removed。
在ODL项目中,模块openflowplugin/applications/topology-manager注册了以上两个通知,并在FlowCapableTopologyExporter.java中,根据收到的通知,对topology datastore进行链路的写入和删除操作,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public void onLinkDiscovered(final LinkDiscovered notification) { processor.enqueueOperation(new TopologyOperation() { @Override public void applyOperation(final ReadWriteTransaction transaction) { final Link link = toTopologyLink(notification); final InstanceIdentifier<Link> path = TopologyManagerUtil.linkPath(link, iiToTopology); transaction.merge(LogicalDatastoreType.OPERATIONAL, path, link, true); } @Override public String toString() { return "onLinkDiscovered"; } }); } public void onLinkRemoved(final LinkRemoved notification) { processor.enqueueOperation(new TopologyOperation() { @Override public void applyOperation(final ReadWriteTransaction transaction) { Optional<Link> linkOptional = Optional.absent(); try { // read that checks if link exists (if we do not do this we might get an exception on delete) linkOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, TopologyManagerUtil.linkPath(toTopologyLink(notification), iiToTopology)).checkedGet(); } catch (ReadFailedException e) { LOG.warn("Error occured when trying to read Link: {}", e.getMessage()); LOG.debug("Error occured when trying to read Link.. ", e); } if (linkOptional.isPresent()) { transaction.delete(LogicalDatastoreType.OPERATIONAL, TopologyManagerUtil.linkPath(toTopologyLink(notification), iiToTopology)); } } |
由于篇幅有限,源码只选择重要部分粘贴,完整源码请从以下链接下载:
https://github.com/opendaylight/openflowplugin/tree/stable/beryllium。
4、总结
通过两篇文章的分析,解析了ODL中LLDP帧的产生,发送以及从LLDP帧中解析link信息和link的老化检测,这就是LLDP机制在ODL中的实现。ODL也正是通过LLDP机制来检测网络中的链路信息,并进而对网络进行管理。
作者简介:徐志阳 2015.09-至今 于北京邮电大学信息光子学与光通信国家重点实验室攻读硕士研究生
鸣谢:本文是作者实习期间所做总结,感谢中国电信北京研究院SDN技术研发中心对本文的指导和支持。