Multiple controller example

 

$ ryu-manager --verbose ryu/app/simple_switch_13.py
$ ryu-manager --verbose --ofp-tcp-listen-port 5555 ryu/app/simple_switch_13.py

I have constructed a Mininet Python topology file, chapter13_mininet_1.py, that specifies two controllers with two switches connected to both the controllers. Each switch two hosts connected to :

...
net = Mininet( controller=RemoteController, switch=OVSKernelSwitch )
c1 = net.addController('c1', controller=RemoteController, ip='127.0.0.1', port=6633)
c2 = net.addController('c2', controller=RemoteController, ip='127.0.0.1', port=5555)
...
s1 = net.addSwitch('s1')
s2 = net.addSwitch('s2')
...
c1.start()
c2.start()
s1.start([c1,c2])
s2.start([c1,c2])
...

We can launch the topology:

$ sudo python mastering_python_networking/Chapter13/chapter13_mininet_1.py
...
mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
h3 h3-eth0:s2-eth2
h4 h4-eth0:s2-eth3
s1 lo: s1-eth1:h1-eth0 s1-eth2:h2-eth0 s1-eth3:s2-eth1
s2 lo: s2-eth1:s1-eth3 s2-eth2:h3-eth0 s2-eth3:h4-eth0
c1
c2

We see that there are actually some duplicated packets on the initial flood:

mininet> h1 ping -c 3 h4
PING 10.0.0.4 (10.0.0.4) 56(84) bytes of data.
64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=34.6 ms
64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=38.4 ms (DUP!)
64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=38.4 ms (DUP!)
64 bytes from 10.0.0.4: icmp_seq=2 ttl=64 time=0.197 ms
64 bytes from 10.0.0.4: icmp_seq=3 ttl=64 time=0.067 ms

--- 10.0.0.4 ping statistics ---
3 packets transmitted, 3 received, +2 duplicates, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.067/22.375/38.480/18.213 ms
mininet>

Let's stop the Mininet topology and clean up the links (you should always do this after you stop your Mininet topology when using API):

$ sudo mn --clean

I have included two Ryu applications, chapter13_switch_1.py and chapter_switch_2.py, each based on simple_switch_13.py that we have seen. However, we made some changes. We added a few more new imports that we will use later on:

from ryu.controller import dpset
from ryu.controller.handler import HANDSHAKE_DISPATCHER
import random

In the initialization, we included the role list as well as a generation ID:

def __init__(self, *args, **kwargs):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self.gen_id = 0
self.role_string_list = ['nochange', 'equal', 'master', 'slave', 'unknown']

We have added additional methods to catch OpenFlow errors with decorator:

@set_ev_cls(ofp_event.EventOFPErrorMsg,
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def on_error_msg(self, ev):
msg = ev.msg
print 'receive a error message: %s' % (msg)

The following section is where we create a function to send role requests from the controller to the switch:

def send_role_request(self, datapath, role, gen_id):
ofp_parser = datapath.ofproto_parser
print 'send a role change request'
print 'role: %s, gen_id: %d' % (self.role_string_list[role], gen_id)
msg = ofp_parser.OFPRoleRequest(datapath, role, gen_id)
datapath.send_msg(msg)

Note that in chapter13_switch_1.py, we assign the controller to MASTER, while in chapter13_switch_2.py, we assign it to SLAVE:

@set_ev_cls(dpset.EventDP, MAIN_DISPATCHER)
def on_dp_change(self, ev):
if ev.enter:
dp = ev.dp
dpid = dp.id
ofp = dp.ofproto
ofp_parser = dp.ofproto_parser

print 'dp entered, id is %s' % (dpid)
self.send_role_request(dp, ofp.OFPCR_ROLE_MASTER, self.gen_id)

We also want to catch the RoleReply messages from the switch to confirm that the controller is now either in master or slave role:

@set_ev_cls(ofp_event.EventOFPRoleReply, MAIN_DISPATCHER)
def on_role_reply(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
role = msg.role

# unknown role
if role < 0 or role > 3:
role = 4
print ''
print 'get a role reply: %s, generation: %d' % (self.role_string_list[role], msg.generation_id)

When we relaunch the Mininet topology, we will be able to see the master and slave assignment and confirmation:

# For master
dp entered, id is 1
send a role change request
role: master, gen_id: 0
...
dp entered, id is 2
send a role change request
role: master, gen_id: 0

# For slave
dp entered, id is 1
send a role change request
role: slave, gen_id: 0
...
dp entered, id is 2
send a role change request
role: slave, gen_id: 0

The switch will now only send the Packet-In message toward the master, with no duplicated flood:

mininet> h1 ping -c3 h4
PING 10.0.0.4 (10.0.0.4) 56(84) bytes of data.
64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=23.8 ms
64 bytes from 10.0.0.4: icmp_seq=2 ttl=64 time=0.311 ms
64 bytes from 10.0.0.4: icmp_seq=3 ttl=64 time=0.059 ms

--- 10.0.0.4 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 0.059/8.070/23.840/11.151 ms

Again, in strategizing for our deployment, the first thing to consider is the number of controllers and their roles. Unfortunately, for both questions, there is no one-size-fits-all formula. You typically make an educated guess in your deployment design, and modify as you gradually improve the work. For general guidance, in some literatures for OpenDaylight and Cisco ACI, they recommend having one master and two slave controllers. If you do not have any preference, that might be a good starting point for controller redundancy.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.164.24