c265deedef
We add a new experimental feature to allow Mininet to run across a cluster of machines. This is currently implemented via a set mix-in classes that provide remote nodes that are implemented via a connection to a remote shell, and remote links which are tunnels across servers. In this preliminary implementation, both control and data connections are made via ssh, but this could change in the future. A MininetCluster class is provided which allows existing code to be used with minimal modification - all that is required is to provide a list of servers to use. A customizable placement algorithm may also be specified. An experimental CLI subclass is also provided to make it easier to examine node placement; status and links commands can also check whether nodes and tunnels are still running. Although this is an experimental feature, it does include a --cluster option to make it convenient to start up a Mininet simulation over a cluster, and a script to assist with setting up the prerequisite authentication via ssh key pairs. The cluster feature is preliminary and missing some obvious important features, such as parallel startup and multiple tunnel types, which we hope to add in the future.
94 lines
3.4 KiB
Python
94 lines
3.4 KiB
Python
#!/usr/bin/python
|
|
|
|
"CLI for Mininet Cluster Edition prototype demo"
|
|
|
|
from mininet.cli import CLI
|
|
from mininet.log import output, error
|
|
|
|
nx, graphviz_layout, plt = None, None, None # Will be imported on demand
|
|
|
|
|
|
class DemoCLI( CLI ):
|
|
"CLI with additional commands for Cluster Edition demo"
|
|
|
|
@staticmethod
|
|
def colorsFor( seq ):
|
|
"Return a list of background colors for a sequence"
|
|
colors = [ 'red', 'lightgreen', 'cyan', 'yellow', 'orange',
|
|
'magenta', 'pink', 'grey', 'brown',
|
|
'white' ]
|
|
slen, clen = len( seq ), len( colors )
|
|
reps = max( 1, slen / clen )
|
|
colors = colors * reps
|
|
colors = colors[ 0 : slen ]
|
|
return colors
|
|
|
|
def do_plot( self, line ):
|
|
"Plot topology colored by node placement"
|
|
# Import networkx if needed
|
|
global nx, plt
|
|
if not nx:
|
|
try:
|
|
import networkx as nx
|
|
import matplotlib.pyplot as plt
|
|
import pygraphviz
|
|
except:
|
|
error( 'plot requires networkx, matplotlib and pygraphviz - '
|
|
'please install them and try again\n' )
|
|
return
|
|
# Make a networkx Graph
|
|
g = nx.Graph()
|
|
mn = self.mn
|
|
servers, hosts, switches = mn.servers, mn.hosts, mn.switches
|
|
hlen, slen = len( hosts ), len( switches )
|
|
nodes = hosts + switches
|
|
g.add_nodes_from( nodes )
|
|
links = [ ( link.intf1.node, link.intf2.node )
|
|
for link in self.mn.links ]
|
|
g.add_edges_from( links )
|
|
# Pick some shapes and colors
|
|
# shapes = hlen * [ 's' ] + slen * [ 'o' ]
|
|
color = dict( zip( servers, self.colorsFor( servers ) ) )
|
|
# Plot it!
|
|
pos = nx.graphviz_layout( g )
|
|
opts = { 'ax': None, 'font_weight': 'bold',
|
|
'width': 2, 'edge_color': 'darkblue' }
|
|
hcolors = [ color[ h.server ] for h in hosts ]
|
|
scolors = [ color[ s.server ] for s in switches ]
|
|
nx.draw_networkx( g, pos=pos, nodelist=hosts, node_size=800, label='host',
|
|
node_color=hcolors, node_shape='s', **opts )
|
|
nx.draw_networkx( g, pos=pos, nodelist=switches, node_size=1000,
|
|
node_color=scolors, node_shape='o', **opts )
|
|
# Get rid of axes, add title, and show
|
|
fig = plt.gcf()
|
|
ax = plt.gca()
|
|
ax.get_xaxis().set_visible( False )
|
|
ax.get_yaxis().set_visible( False )
|
|
fig.canvas.set_window_title( 'Mininet')
|
|
plt.title( 'Node Placement', fontweight='bold' )
|
|
plt.show()
|
|
|
|
def do_status( self, line ):
|
|
"Report on node shell status"
|
|
nodes = self.mn.hosts + self.mn.switches
|
|
for node in nodes:
|
|
node.shell.poll()
|
|
exited = [ node for node in nodes
|
|
if node.shell.returncode is not None ]
|
|
if exited:
|
|
for node in exited:
|
|
output( '%s has exited with code %d\n'
|
|
% ( node, node.shell.returncode ) )
|
|
else:
|
|
output( 'All nodes are still running.\n' )
|
|
|
|
|
|
def do_placement( self, line ):
|
|
"Describe node placement"
|
|
mn = self.mn
|
|
nodes = mn.hosts + mn.switches + mn.controllers
|
|
for server in mn.servers:
|
|
names = [ n.name for n in nodes if hasattr( n, 'server' )
|
|
and n.server == server ]
|
|
output( '%s: %s\n' % ( server, ' '.join( names ) ) )
|