On in part 4 we set-up Ryu to be an L2 switch and it applied flow rules to the LINC switch. The traffic source which triggered the rules was port eth0 which effectively is the control port since this connects the Raspberry Pi to my network and ultimately to the Ryu controller. The flows were therefore applied as a result of noise and chatter on the local LAN.
For our first very simple experiment we need to have a more controlled environment so let's modify the LINC config so that eth0 is solely to connect the switch to the controller.
To shutdown LINC
(linc@raspberrypi)2> init:stop().
Let's edit the LINC config file
sudo vi /home/pi/LINC-Switch/rel/linc/releases/1.0/sys.config
{ports,
[
%% - regular hardware interface
{port, 1, [{interface, "eth1"}]},
{port, 2, [{interface, "eth2"}]},
%% {port, 4, [{interface, "eth0"}]}
{port, 3, [{interface, "wlan0"}]}
%% - hardware interface with explicit type
Comment out port 4 (I moved it as the comma on the last entry for port 3 causes the config file to fail).
Restart the switch
pi@raspberrypi ~/LINC-Switch $ sudo rel/linc/bin/linc console
So I now have 3 ports for traffic on the Pi. I need a traffic source so I connected a laptop via a cable to eth1. There is no DHCP so no IP addresses on the laptop will need be assigned so you will need to change the IP address on the laptop to be a static IP address. I set mine to 192.168.1.130/24 with a default gateway of 192.168.1.1.
So the controller spots the laptop
> installing new source mac received from port 1
If we now look at the flow tables on the switch we can see what's happening in more detail and understand.
Let's view LINCs flow table:
(linc@raspberrypi)1> ets:tab2list(linc:lookup(0, flow_table_0)).
[{flow_entry,{0,#Ref<0.0.0.374>},
0,
{ofp_match,[]},
<<0,0,0,0,0,0,0,0>>,
[],
{1370,616692,527826},
{infinity,0,0},
{infinity,0,0},
[{ofp_instruction_write_actions,4,
[{ofp_action_output,16,controller,65535}]}]},
{flow_entry,{123,#Ref<0.0.0.381>},
123,
{ofp_match,[{ofp_field,openflow_basic,in_port,false,
<<0,0,0,1>>,
undefined},
{ofp_field,openflow_basic,eth_src,false,
<<32,207,48,0,192,96>>,
undefined}]},
<<0,0,0,0,0,0,0,0>>,
[],
{1370,616842,124920},
{infinity,0,0},
{infinity,0,0},
[{ofp_instruction_goto_table,6,1}]}]
The line with
{ofp_field,openflow_basic,eth_src,false,
<<32,207,48,0,192,96>>,
undefined}]},
This is the laptop's MAC address in decimal notation 20:CF:30:00:C0:60
(linc@raspberrypi)1> ets:tab2list(linc:lookup(0, linc_ports)).
[{linc_port,1,<0.164.0>},
{linc_port,2,<0.161.0>},
{linc_port,3,<0.157.0>}]
OK. LINC isn't the most user friendly if you are a network engineer. There are plans to improve this and adopt a more familiar user interface like Cisco IOS.
Right. Let's stop ryu and install a really simple controller configuration to show how things work.
ryu is written in python. I have to admit that it's taking me a while to get used to python syntax having used c, php and other languages that use {} structures for function declarations. Python uses just space or tabs to identify what's a function ! Seems crazy to me but that's how it's done.
A packet arrives at the switch. The switch checks what rules (flows) have been defined for the arriving packet. The controller hasnt actually installed any so it then refers the packet to the ryu controller.
ryu now dissects the packet passed over the OpenFlow protocol and the above programme tells ryu how to process packets.
The function packet_in_handler is called.
The key line here is
What this is actually saying is to send the arriving packet to all interfaces. We are building a hub which is exactly what it does - it floods arriving packets to all ports. The final line commits this.
Now we would never do this in reality since it is a massive overhead. The switch will copy every single packet to the controller asking what to do with it. The switch never learns anything!
Now given in a real network the controller may be remote from the switch, you can see this would introduce massive latency and massive traffic duplication !
The point of this is really to show the logic of how OpenFlow works.
We can run ryu with more verbose logging to see more about what it is doing
Here's what it comes back with:
Ignore the reference to L2Switch - this is a hub. L2Switch is from the class declaration at the beginning - I copied this example.
You can see ryu is initialising, then it connects to the Raspberry Pi OpenFlow switch running at 192.168.15
It negotiates to use the OF1.3 protocol (0x04)
The Raspberry Pi will report it has also connected to the controller.
Now on the laptop connected to the Raspberry Pi, if I set ping running to ping some address, this will be forwarded to the controller. In the controller window you'll see each ping packet event showing in the verbose log
In the next post I'll evolve our simple hub to at least not broadcast out of every port.
I have a Raspberry Pi B+ with Erlang/LINC-Switch.
ReplyDeleteI have a notebook with Ryu.
LINC-Switch closes connection "because of version or bad message".
Can you help me?
Tks, Edison.
hi, did you try with other controllers such as opendaylight or onos?
ReplyDeletehello,
ReplyDeleteI have a Raspberry Pi-3 with Erlang/LINC switch and also installed Ryu following this tutorial blog.
But I get a crash report when starting the switch and so we are unable to connect the switch and the controller.I get the following crash report. I need help resolving this problem
05:06:15.844 ^[[1;31m[error] CRASH REPORT Process <0.182.0> with 0 neighbours exited with reason: call to undefined function application:get_env(of_protocol, no_multipart, false) in gen_server:init_it/6 line 328^[[0m