import urllib2
from functools import partial
-from mininet.net import Dockernet
+from mininet.net import Containernet
from mininet.node import Controller, DefaultController, OVSSwitch, OVSKernelSwitch, Docker, RemoteController
from mininet.cli import CLI
from mininet.link import TCLink
from emuvim.dcemulator.node import Datacenter, EmulatorCompute
from emuvim.dcemulator.resourcemodel import ResourceModelRegistrar
-class DCNetwork(Dockernet):
+class DCNetwork(Containernet):
"""
- Wraps the original Mininet/Dockernet class and provides
+ Wraps the original Mininet/Containernet class and provides
methods to add data centers, switches, etc.
This class is used by topology definition scripts.
"""
def __init__(self, controller=RemoteController, monitor=False,
+ enable_learning = True, # in case of RemoteController (Ryu), learning switch behavior can be turned off/on
dc_emulation_max_cpu=1.0, # fraction of overall CPU time for emulation
dc_emulation_max_mem=512, # emulation max mem in MB
**kwargs):
"""
- Create an extended version of a Dockernet network
+ Create an extended version of a Containernet network
:param dc_emulation_max_cpu: max. CPU time used by containers in data centers
:param kwargs: path through for Mininet parameters
:return:
self.dcs = {}
# call original Docker.__init__ and setup default controller
- Dockernet.__init__(
- self, switch=OVSKernelSwitch, **kwargs)
+ Containernet.__init__(
+ self, switch=OVSKernelSwitch, controller=controller, **kwargs)
+
# Ryu management
self.ryu_process = None
if controller == RemoteController:
# start Ryu controller
- self.startRyu()
+ self.startRyu(learning_switch=enable_learning)
# add the specified controller
self.addController('c0', controller=controller)
params["params2"]["ip"] = self.getNextIp()
# ensure that we allow TCLinks between data centers
# TODO this is not optimal, we use cls=Link for containers and TCLink for data centers
- # see Dockernet issue: https://github.com/mpeuster/dockernet/issues/3
+ # see Containernet issue: https://github.com/mpeuster/containernet/issues/3
if "cls" not in params:
params["cls"] = TCLink
- link = Dockernet.addLink(self, node1, node2, **params)
+ link = Containernet.addLink(self, node1, node2, **params)
# try to give container interfaces a default id
node1_port_id = node1.ports[link.intf1]
# add edge and assigned port number to graph in both directions between node1 and node2
# port_id: id given in descriptor (if available, otherwise same as port)
- # port: portnumber assigned by Dockernet
+ # port: portnumber assigned by Containernet
attr_dict = {}
# possible weight metrics allowed by TClink class:
Wrapper for addDocker method to use custom container class.
"""
self.DCNetwork_graph.add_node(label)
- return Dockernet.addDocker(self, label, cls=EmulatorCompute, **params)
+ return Containernet.addDocker(self, label, cls=EmulatorCompute, **params)
def removeDocker( self, label, **params ):
"""
Wrapper for removeDocker method to update graph.
"""
self.DCNetwork_graph.remove_node(label)
- return Dockernet.removeDocker(self, label, **params)
+ return Containernet.removeDocker(self, label, **params)
def addSwitch( self, name, add_to_graph=True, **params ):
"""
"""
if add_to_graph:
self.DCNetwork_graph.add_node(name)
- return Dockernet.addSwitch(self, name, protocols='OpenFlow10,OpenFlow12,OpenFlow13', **params)
+ return Containernet.addSwitch(self, name, protocols='OpenFlow10,OpenFlow12,OpenFlow13', **params)
def getAllContainers(self):
"""
# start
for dc in self.dcs.itervalues():
dc.start()
- Dockernet.start(self)
+ Containernet.start(self)
def stop(self):
self.monitor_agent.stop()
# stop emulator net
- Dockernet.stop(self)
+ Containernet.stop(self)
# stop Ryu controller
self.stopRyu()
if cmd == 'add-flow':
ret = self._chainAddFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface, **kwargs)
if kwargs.get('bidirectional'):
- return ret +'\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
+ ret = ret +'\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
elif cmd == 'del-flows': # TODO: del-flow to be implemented
ret = self._chainAddFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface, **kwargs)
if kwargs.get('bidirectional'):
- return ret + '\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
+ ret = ret + '\n' + self._chainAddFlow(vnf_dst_name, vnf_src_name, vnf_dst_interface, vnf_src_interface, **kwargs)
else:
- return "Command unknown"
+ ret = "Command unknown"
+
+ return ret
def _chainAddFlow(self, vnf_src_name, vnf_dst_name, vnf_src_interface=None, vnf_dst_interface=None, **kwargs):
kwargs['vlan'] = vlan
kwargs['path'] = path
kwargs['current_hop'] = current_hop
- ## set flow entry via ovs-ofctl
- #self._set_flow_entry_dpctl(current_node, switch_inport_nr, switch_outport_nr, **kwargs)
- ## set flow entry via ryu rest api
- self._set_flow_entry_ryu_rest(current_node, switch_inport_nr, switch_outport_nr, **kwargs)
+
+ if self.controller == RemoteController:
+ ## set flow entry via ryu rest api
+ self._set_flow_entry_ryu_rest(current_node, switch_inport_nr, switch_outport_nr, **kwargs)
+ else:
+ ## set flow entry via ovs-ofctl
+ self._set_flow_entry_dpctl(current_node, switch_inport_nr, switch_outport_nr, **kwargs)
+
+
# take first link between switches by default
if isinstance( next_node, OVSSwitch ):
flow = {}
flow['dpid'] = int(node.dpid, 16)
+
if cookie:
flow['cookie'] = int(cookie)
# http://ryu.readthedocs.io/en/latest/app/ofctl_rest.html#add-a-flow-entry
if cmd == 'add-flow':
prefix = 'stats/flowentry/add'
- action = {}
- action['type'] = 'OUTPUT'
- action['port'] = switch_outport_nr
- flow['actions'].append(action)
if vlan != None:
if path.index(current_hop) == 0: # first node
action = {}
action['type'] = 'PUSH_VLAN' # Push a new VLAN tag if a input frame is non-VLAN-tagged
action['ethertype'] = 33024 # Ethertype 0x8100(=33024): IEEE 802.1Q VLAN-tagged frame
+ flow['actions'].append(action)
+ action = {}
action['type'] = 'SET_FIELD'
action['field'] = 'vlan_vid'
action['value'] = vlan
flow['actions'].append(action)
else: # middle nodes
match += ',dl_vlan=%s' % vlan
- #flow['match'] = self._parse_match(match)
+ # output action must come last
+ action = {}
+ action['type'] = 'OUTPUT'
+ action['port'] = switch_outport_nr
+ flow['actions'].append(action)
+
elif cmd == 'del-flows':
- #del(flow['actions'])
prefix = 'stats/flowentry/delete'
+
+ # if cookie is given, only delete flows by cookie
+ # do not specify other match -> also other cookies can be matched
if cookie:
- flow['cookie_mask'] = cookie
- #if cookie is None:
- # flow['match'] = self._parse_match(match)
+ flow['cookie_mask'] = int('0xffffffffffffffff', 16) # need full mask to match complete cookie
action = {}
action['type'] = 'OUTPUT'
switch_outport_nr, cmd))
# start Ryu Openflow controller as Remote Controller for the DCNetwork
- def startRyu(self):
+ def startRyu(self, learning_switch=True):
# start Ryu controller with rest-API
python_install_path = site.getsitepackages()[0]
ryu_path = python_install_path + '/ryu/app/simple_switch_13.py'
ryu_of_port = '6653'
ryu_cmd = 'ryu-manager'
FNULL = open("/tmp/ryu.log", 'w')
- self.ryu_process = Popen([ryu_cmd, ryu_path, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
- # no learning switch
- #self.ryu_process = Popen([ryu_cmd, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
+ if learning_switch:
+ self.ryu_process = Popen([ryu_cmd, ryu_path, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
+ else:
+ # no learning switch
+ self.ryu_process = Popen([ryu_cmd, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
time.sleep(1)
def stopRyu(self):
self.ryu_process.kill()
def ryu_REST(self, prefix, dpid=None, data=None):
- if dpid:
- url = self.ryu_REST_api + '/' + str(prefix) + '/' + str(dpid)
- else:
- url = self.ryu_REST_api + '/' + str(prefix)
- if data:
- #logging.info('POST: {0}'.format(str(data)))
- req = urllib2.Request(url, str(data))
- else:
- req = urllib2.Request(url)
+ try:
+ if dpid:
+ url = self.ryu_REST_api + '/' + str(prefix) + '/' + str(dpid)
+ else:
+ url = self.ryu_REST_api + '/' + str(prefix)
+ if data:
+ #logging.info('POST: {0}'.format(str(data)))
+ req = urllib2.Request(url, str(data))
+ else:
+ req = urllib2.Request(url)
- ret = urllib2.urlopen(req).read()
- return ret
+ ret = urllib2.urlopen(req).read()
+ return ret
+ except:
+ logging.info('error url: {0}'.format(str(url)))
+ if data: logging.info('error POST: {0}'.format(str(data)))
# need to respect that some match fields must be integers
# http://ryu.readthedocs.io/en/latest/app/ofctl_rest.html#description-of-match-and-actions