在上一篇文章中介绍Floodlight怎样做拓扑发现,这篇文章介绍一下网络拓扑是怎样形成的。TopologyManager这个类负责网络拓扑的产生。这个类首先实现了IFloodlightModule这个接口,是Floodlight的一个模块。其实是实现了ILinkDiscoveryListener用于监听网络中链路的变化;还实现了IOFMessageListener用于接收和处理网络包。
和其他的Floodlight模块一样,首先看启动方法startup。
@Override
public void startUp(FloodlightModuleContext context) {
clearCurrentTopology();
// Initialize role to floodlight provider role.
this.role = floodlightProviderService.getRole();
ScheduledExecutorService ses = threadPoolService.getScheduledExecutor();
newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker());
if (role != HARole.STANDBY) {
newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS);
}
linkDiscoveryService.addListener(this);
floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
floodlightProviderService.addHAListener(this.haListener);
addRestletRoutable();
}
/**
* Clears the current topology. Note that this does NOT
* send out updates.
*/
public void clearCurrentTopology() {
this.clear();
linksUpdated = true;
dtLinksUpdated = true;
tunnelPortsUpdated = true;
createNewInstance("startup");
lastUpdateTime = new Date();
}
clear方法清理所以内存中保存的节点链路拓扑信息。
public void clear() {
switchPorts.clear();
tunnelPorts.clear();
switchPortLinks.clear();
portBroadcastDomainLinks.clear();
directLinks.clear();
}
关于这个nosql内存数据库下一章讲解。
当清理完数据后开始创建新的拓扑
/**
* This function computes a new topology instance.
* It ignores links connected to all broadcast domain ports
* and tunnel ports. The method returns if a new instance of
* topology was created or not.
*/
protected boolean createNewInstance(String reason) {
Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>();
if (!linksUpdated) return false;
Map<NodePortTuple, Set<Link>> openflowLinks;
openflowLinks =
new HashMap<NodePortTuple, Set<Link>>();
Set<NodePortTuple> nptList = switchPortLinks.keySet();
if (nptList != null) {
for (NodePortTuple npt : nptList) {
Set<Link> linkSet = switchPortLinks.get(npt);
if (linkSet == null) continue;
openflowLinks.put(npt, new HashSet<Link>(linkSet));
}
}
// Identify all broadcast domain ports.
// Mark any port that has inconsistent set of links
// as broadcast domain ports as well.
Set<NodePortTuple> broadcastDomainPorts =
identifyBroadcastDomainPorts();
// Remove all links incident on broadcast domain ports.
for (NodePortTuple npt : broadcastDomainPorts) {
if (switchPortLinks.get(npt) == null) continue;
for (Link link : switchPortLinks.get(npt)) {
removeLinkFromStructure(openflowLinks, link);
}
}
// Remove all tunnel links.
for (NodePortTuple npt : tunnelPorts) {
if (switchPortLinks.get(npt) == null) continue;
for (Link link : switchPortLinks.get(npt)) {
removeLinkFromStructure(openflowLinks, link);
}
}
//switchPorts contains only ports that are part of links. Calculation of broadcast ports needs set of all ports.
Map<DatapathId, Set<OFPort>> allPorts = new HashMap<DatapathId, Set<OFPort>>();
;
for (DatapathId sw : switchPorts.keySet()) {
allPorts.put(sw, this.getPorts(sw));
}
TopologyInstance nt = new TopologyInstance(switchPorts,
blockedPorts,
openflowLinks,
broadcastDomainPorts,
tunnelPorts,
switchPortLinks,
allPorts,
portBroadcastDomainLinks);
nt.compute();
// We set the instances with and without tunnels to be identical.
// If needed, we may compute them differently.
currentInstance = nt;
currentInstanceWithoutTunnels = nt;
TopologyEventInfo topologyInfo =
new TopologyEventInfo(0, nt.getClusters().size(),
new HashMap<DatapathId, List<NodePortTuple>>(),
0);
eventCategory.newEventWithFlush(new TopologyEvent(reason, topologyInfo));
return true;
}
这个方法有七步看代码如下
public void compute() {
// Step 1: Compute clusters ignoring broadcast domain links
// Create nodes for clusters in the higher level topology
// Must ignore blocked links.
identifyOpenflowDomains();
// Step 1.1: Add links to clusters
// Avoid adding blocked links to clusters
addLinksToOpenflowDomains();
// Step 2. Compute shortest path trees in each cluster for
// unicast routing. The trees are rooted at the destination.
// Cost for tunnel links and direct links are the same.
calculateShortestPathTreeInClusters();
// Step 3. Compute broadcast tree in each cluster.
// Cost for tunnel links are high to discourage use of
// tunnel links. The cost is set to the number of nodes
// in the cluster + 1, to use as minimum number of
// clusters as possible.
calculateBroadcastNodePortsInClusters();
// Step 4. Compute e2e shortest path trees on entire topology for unicast routing.
// The trees are rooted at the destination.
// Cost for tunnel links and direct links are the same.
calculateAllShortestPaths();
// Compute the archipelagos (def: cluster of islands). An archipelago will
// simply be a group of connected islands. Each archipelago will have its own
// finiteBroadcastTree which will be randomly chosen.
calculateArchipelagos();
// Step 5. Compute broadcast tree for the whole topology (needed to avoid loops).
// Cost for tunnel links are high to discourage use of
// tunnel links. The cost is set to the number of nodes
// in the cluster + 1, to use as minimum number of
// clusters as possible.
calculateAllBroadcastNodePorts();
// Step 6. Compute set of ports for broadcasting. Edge ports are included.
calculateBroadcastPortMap();
// Step 7. print topology.
printTopology();
}
addLinksToOpenflowDomains添加集群直接的的link
calculateShortestPathTreeInClusters通过给链路添加权重在通clusterDijkstra最短路径算法计算拓扑最短路径
后面几个方法是整个网络的最短路径计算,详细部分文章后面一一解说