"""
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):
# call original Docker.__init__ and setup default controller
Containernet.__init__(
- self, switch=OVSKernelSwitch, **kwargs)
+ 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)
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)
+ if data: logging.info('log POST: {0}'.format(str(data)))
+ 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
"""
1. Create a data center network object (DCNetwork) with monitoring enabled
"""
- net = DCNetwork(monitor=True)
+ net = DCNetwork(monitor=True, enable_learning=False)
"""
1b. add a monitoring agent to the DCNetwork
3. You can add additional SDN switches for data center
interconnections to the network.
"""
- #s1 = net.addSwitch("s1")
+ s1 = net.addSwitch("s1")
"""
4. Add links between your data centers and additional switches
to define you topology.
These links can use Mininet's features to limit bw, add delay or jitter.
"""
- net.addLink(dc1, dc2, delay="10ms")
+ #net.addLink(dc1, dc2, delay="10ms")
#net.addLink(dc1, dc2)
+ net.addLink(dc1, s1)
+ net.addLink(s1, dc2)
#net.addLink("datacenter1", s1, delay="20ms")
#net.addLink(s1, dc3)
#net.addLink(s1, "datacenter4")
def createNet(
self,
nswitches=0, ndatacenter=0, nhosts=0, ndockers=0,
- autolinkswitches=False, controller=Controller):
+ autolinkswitches=False, controller=Controller, **kwargs):
"""
Creates a Mininet instance and automatically adds some
nodes to it.
for our tests. Only use other controllers if you want to test
specific controller functionality.
"""
- self.net = DCNetwork(controller=controller)
+ self.net = DCNetwork(controller=controller, **kwargs)
# add some switches
- for i in range(0, nswitches):
+ # start from s1 because ovs does not like to have dpid = 0
+ # and switch name-number is being used by mininet to set the dpid
+ for i in range(1, nswitches+1):
self.s.append(self.net.addSwitch('s%d' % i))
# if specified, chain all switches
if autolinkswitches:
import unittest
from emuvim.dcemulator.node import EmulatorCompute
from emuvim.test.base import SimpleTestTopology
+from mininet.node import RemoteController
#@unittest.skip("disabled topology tests for development")
# stop Mininet network
self.stopNet()
+class testEmulatorNetworking( SimpleTestTopology ):
+
+ def testSDNChainingSingleService(self):
+ """
+ Create a two data centers and interconnect them with additional
+ switches between them.
+ Uses Ryu SDN controller.
+ Connect the Docker hosts to different datacenters and setup the links between.
+ """
+ # create network
+ self.createNet(
+ nswitches=3, ndatacenter=2, nhosts=0, ndockers=0,
+ autolinkswitches=True,
+ controller=RemoteController,
+ enable_learning=False)
+ # setup links
+ self.net.addLink(self.dc[0], self.s[0])
+ self.net.addLink(self.s[2], self.dc[1])
+ # start Mininet network
+ self.startNet()
+
+ # add compute resources
+ vnf1 = self.dc[0].startCompute("vnf1", network=[{'id':'intf1', 'ip':'10.0.10.1/24'}])
+ vnf2 = self.dc[1].startCompute("vnf2", network=[{'id':'intf2', 'ip':'10.0.10.2/24'}])
+ # check number of running nodes
+ self.assertTrue(len(self.getContainernetContainers()) == 2)
+ self.assertTrue(len(self.net.hosts) == 2)
+ self.assertTrue(len(self.net.switches) == 5)
+ # check status
+ # check get status
+ s1 = self.dc[0].containers.get("vnf1").getStatus()
+ self.assertTrue(s1["name"] == "vnf1")
+ self.assertTrue(s1["state"]["Running"])
+ self.assertTrue(s1["network"][0]['intf_name'] == 'intf1')
+ self.assertTrue(s1["network"][0]['ip'] == '10.0.10.1')
+
+ s2 = self.dc[1].containers.get("vnf2").getStatus()
+ self.assertTrue(s2["name"] == "vnf2")
+ self.assertTrue(s2["state"]["Running"])
+ self.assertTrue(s2["network"][0]['intf_name'] == 'intf2')
+ self.assertTrue(s2["network"][0]['ip'] == '10.0.10.2')
+
+ # setup links
+ self.net.setChain('vnf1', 'vnf2', 'intf1', 'intf2', bidirectional=True, cmd='add-flow')
+ # check connectivity by using ping
+ self.assertTrue(self.net.ping([vnf1, vnf2]) <= 0.0)
+ # stop Mininet network
+ self.stopNet()
+
+ def testSDNChainingMultiService(self):
+ """
+ Create a two data centers and interconnect them with additional
+ switches between them.
+ Uses Ryu SDN controller.
+ Setup 2 services and setup isolated paths between them
+ Delete only the first service, and check that other one still works
+ """
+ # create network
+ self.createNet(
+ nswitches=3, ndatacenter=2, nhosts=0, ndockers=0,
+ autolinkswitches=True,
+ controller=RemoteController,
+ enable_learning=False)
+ # setup links
+ self.net.addLink(self.dc[0], self.s[0])
+ self.net.addLink(self.s[2], self.dc[1])
+ # start Mininet network
+ self.startNet()
+
+ ## First Service
+ # add compute resources
+ vnf1 = self.dc[0].startCompute("vnf1", network=[{'id': 'intf1', 'ip': '10.0.10.1/24'}])
+ vnf2 = self.dc[1].startCompute("vnf2", network=[{'id': 'intf2', 'ip': '10.0.10.2/24'}])
+ # setup links
+ self.net.setChain('vnf1', 'vnf2', 'intf1', 'intf2', bidirectional=True, cmd='add-flow', cookie=1)
+ # check connectivity by using ping
+ self.assertTrue(self.net.ping([vnf1, vnf2]) <= 0.0)
+
+ ## Second Service
+ # add compute resources
+ vnf11 = self.dc[0].startCompute("vnf11", network=[{'id': 'intf1', 'ip': '10.0.20.1/24'}])
+ vnf22 = self.dc[1].startCompute("vnf22", network=[{'id': 'intf2', 'ip': '10.0.20.2/24'}])
+
+ # check number of running nodes
+ self.assertTrue(len(self.getContainernetContainers()) == 4)
+ self.assertTrue(len(self.net.hosts) == 4)
+ self.assertTrue(len(self.net.switches) == 5)
+
+ # setup links
+ self.net.setChain('vnf11', 'vnf22', 'intf1', 'intf2', bidirectional=True, cmd='add-flow', cookie=2)
+ # check connectivity by using ping
+ self.assertTrue(self.net.ping([vnf11, vnf22]) <= 0.0)
+ # check first service cannot ping second service
+ self.assertTrue(self.net.ping([vnf1, vnf22]) > 0.0)
+ self.assertTrue(self.net.ping([vnf2, vnf11]) > 0.0)
+
+ # delete the first service chain
+ self.net.setChain('vnf1', 'vnf2', 'intf1', 'intf2', bidirectional=True, cmd='del-flows', cookie=1)
+ # check connectivity of first service is down
+ self.assertTrue(self.net.ping([vnf1, vnf2]) > 0.0)
+ #time.sleep(100)
+ # check connectivity of second service is still up
+ self.assertTrue(self.net.ping([vnf11, vnf22]) <= 0.0)
+
+ # stop Mininet network
+ self.stopNet()
#@unittest.skip("disabled compute tests for development")
class testEmulatorCompute( SimpleTestTopology ):