The most succinct demonstration of OpenFlow on OpenVSwitch is the
Openflow version 1.3 tutorial on SDN Hub.
They make use of a pre-packaged VM for their demo. Which is easy enough to do with basic packages:
$ apt-get update
$ apt-get install openvswitch-switch python-openvswitch ryu-bin python-ryu mininet tshark
The openvswitch installation will install and start up the openvswitch service. OpenVSwitch does regular switching and can also act as an OpenFlow agent. For the purposes of the demonstration,
openvswitch should be set for OpenFlow version 1.3.
$ ovs-vsctl set bridge s1 protocols=OpenFlow13
An OpenFlow agent needs to be controlled by an OpenFlow controller. A large number of them are available. OpenSource.
ClosedSource. or in between.
I use SaltStack for provisioning, automation and orchestration. It is a Python based tool. To stay with the theme of Python,
I have selected RYU as a controller, which is developed in Python. The RYU install comes with a number of example scripts.
A simple switch controller can be started with:
$ ryu-manager --verbose /usr/lib/python2.7/dist-packages/ryu/app/simple_switch_13.py
It listens on port 6653 and 6633:
t# netstat -ln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:6653 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:6633 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
udp 0 0 0.0.0.0:68 0.0.0.0:*
Mininet is a nice little utility which makes use of Linux' namespace and cgroups to setup emulated hosts and uses openvswitch to handle switching. This example makes use of a simple switch with three hosts. When starting up, it initializes the topology, and then provides a prompt for running commands.
$ mn --topo single,3 --mac --controller remote --switch ovsk,protocols=OpenFlow13
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2 h3
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1) (h3, s1)
*** Configuring hosts
h1 h2 h3
*** Starting controller
c0
*** Starting 1 switches
s1 ...
*** Starting CLI:
mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=19.2 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.312 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.082 ms
^C
--- 10.0.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2028ms
rtt min/avg/max/mdev = 0.082/6.534/19.209/8.963 ms
mininet>
Additional ports for communicating:
$ netstat -ln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:6653 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:6633 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:6634 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
udp 0 0 0.0.0.0:68 0.0.0.0:*
Dumping flows of the resulting actions:
# ovs-ofctl dump-flows s1 -O OpenFlow13
OFPST_FLOW reply (OF1.3) (xid=0x2):
cookie=0x0, duration=185.861s, table=0, n_packets=24, n_bytes=1856, priority=0 actions=CONTROLLER:65535
cookie=0x0, duration=180.186s, table=0, n_packets=5, n_bytes=378, priority=1,in_port=2,dl_dst=00:00:00:00:00:01 actions=output:1
cookie=0x0, duration=180.181s, table=0, n_packets=4, n_bytes=336, priority=1,in_port=1,dl_dst=00:00:00:00:00:02 actions=output:2
During a ping, an example of an unmatched packet being told to flood:
Frame 91: 178 bytes on wire (1424 bits), 178 bytes captured (1424 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 49136, Dst Port: 6633, Seq: 3041, Ack: 1105, Len: 112
OpenFlow 1.3
Version: 1.3 (0x04)
Type: OFPT_PACKET_IN (10)
Length: 112
Transaction ID: 0
Buffer ID: 278
Total length: 70
Reason: OFPR_NO_MATCH (0)
Table ID: 0
Cookie: 0x0000000000000000
Match
Type: OFPMT_OXM (1)
Length: 12
OXM field
Class: OFPXMC_OPENFLOW_BASIC (0x8000)
0000 000. = Field: OFPXMT_OFB_IN_PORT (0)
.... ...0 = Has mask: False
Length: 4
Value: 2
Pad: 00000000
Pad: 0000
Data
Ethernet II, Src: 00:00:00_00:00:02 (00:00:00:00:00:02), Dst: IPv6mcast_02 (33:33:00:00:00:02)
Destination: IPv6mcast_02 (33:33:00:00:00:02)
Address: IPv6mcast_02 (33:33:00:00:00:02)
.... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
.... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)
Source: 00:00:00_00:00:02 (00:00:00:00:00:02)
Address: 00:00:00_00:00:02 (00:00:00:00:00:02)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
Type: IPv6 (0x86dd)
Internet Protocol Version 6, Src: fe80::200:ff:fe00:2, Dst: ff02::2
0110 .... = Version: 6
.... 0000 0000 .... .... .... .... .... = Traffic class: 0x00 (DSCP: CS0, ECN: Not-ECT)
.... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
.... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
.... .... .... 0000 0000 0000 0000 0000 = Flow label: 0x00000
Payload length: 16
Next header: ICMPv6 (58)
Hop limit: 255
Source: fe80::200:ff:fe00:2
[Source SA MAC: 00:00:00_00:00:02 (00:00:00:00:00:02)]
Destination: ff02::2
[Source GeoIP: Unknown]
[Destination GeoIP: Unknown]
Internet Control Message Protocol v6
Type: Router Solicitation (133)
Code: 0
Checksum: 0x7b2a [correct]
[Checksum Status: Good]
Reserved: 00000000
ICMPv6 Option (Source link-layer address : 00:00:00:00:00:02)
Type: Source link-layer address (1)
Length: 1 (8 bytes)
Link-layer address: 00:00:00_00:00:02 (00:00:00:00:00:02)
Frame 92: 106 bytes on wire (848 bits), 106 bytes captured (848 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 6633, Dst Port: 49136, Seq: 1105, Ack: 3153, Len: 40
OpenFlow 1.3
Version: 1.3 (0x04)
Type: OFPT_PACKET_OUT (13)
Length: 40
Transaction ID: 1001008312
Buffer ID: 278
In port: 2
Actions length: 16
Pad: 000000000000
Action
Type: OFPAT_OUTPUT (0)
Length: 16
Port: OFPP_FLOOD (0xfffffffb)
Max length: 65509
Pad: 000000000000
OpenFlow control packets can be decoded via tshark. Here is an example port status decode:
$ tshark -O openflow_v4 -V -i lo not port 22
Frame 395: 146 bytes on wire (1168 bits), 146 bytes captured (1168 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 49116, Dst Port: 6633, Seq: 1201, Ack: 1041, Len: 80
OpenFlow 1.3
Version: 1.3 (0x04)
Type: OFPT_PORT_STATUS (12)
Length: 80
Transaction ID: 0
Reason: OFPPR_DELETE (1)
Pad: 00000000000000
Port
Port no: 2
Pad: 00000000
Hw addr: 16:2a:cf:6c:14:fd (16:2a:cf:6c:14:fd)
Pad: 0000
Name: s1-eth2
Config: 0x00000000
.... .... .... .... .... .... .... ...0 = OFPPC_PORT_DOWN: False
.... .... .... .... .... .... .... .0.. = OFPPC_NO_RECV: False
.... .... .... .... .... .... ..0. .... = OFPPC_NO_FWD: False
.... .... .... .... .... .... .0.. .... = OFPPC_NO_PACKET_IN: False
State: 0x00000000
.... .... .... .... .... .... .... ...0 = OFPPS_LINK_DOWN: False
.... .... .... .... .... .... .... ..0. = OFPPS_BLOCKED: False
.... .... .... .... .... .... .... .0.. = OFPPS_LIVE: False
Current: 0x00000840
.... .... .... .... .... .... .... ...0 = OFPPF_10MB_HD: False
.... .... .... .... .... .... .... ..0. = OFPPF_10MB_FD: False
.... .... .... .... .... .... .... .0.. = OFPPF_100MB_HD: False
.... .... .... .... .... .... .... 0... = OFPPF_100MB_FD: False
.... .... .... .... .... .... ...0 .... = OFPPF_1GB_HD: False
.... .... .... .... .... .... ..0. .... = OFPPF_1GB_FD: False
.... .... .... .... .... .... .1.. .... = OFPPF_10_GB_FD: True
.... .... .... .... .... .... 0... .... = OFPPF_40GB_FD: False
.... .... .... .... .... ...0 .... .... = OFPPF_100_GB_FD: False
.... .... .... .... .... ..0. .... .... = OFPPF_1TB_FD: False
.... .... .... .... .... .0.. .... .... = OFPPF_OTHER: False
.... .... .... .... .... 1... .... .... = OFPPF_COPPER: True
.... .... .... .... ...0 .... .... .... = OFPPF_FIBER: False
.... .... .... .... ..0. .... .... .... = OFPPF_AUTONEG: False
.... .... .... .... .0.. .... .... .... = OFPPF_PAUSE: False
.... .... .... .... 0... .... .... .... = OFPPF_PAUSE_ASYM: False
Advertised: 0x00000000
.... .... .... .... .... .... .... ...0 = OFPPF_10MB_HD: False
.... .... .... .... .... .... .... ..0. = OFPPF_10MB_FD: False
.... .... .... .... .... .... .... .0.. = OFPPF_100MB_HD: False
.... .... .... .... .... .... .... 0... = OFPPF_100MB_FD: False
.... .... .... .... .... .... ...0 .... = OFPPF_1GB_HD: False
.... .... .... .... .... .... ..0. .... = OFPPF_1GB_FD: False
.... .... .... .... .... .... .0.. .... = OFPPF_10_GB_FD: False
.... .... .... .... .... .... 0... .... = OFPPF_40GB_FD: False
.... .... .... .... .... ...0 .... .... = OFPPF_100GB_FD: False
.... .... .... .... .... ..0. .... .... = OFPPF_1TB_FD: False
.... .... .... .... .... .0.. .... .... = OFPPF_OTHER: False
.... .... .... .... .... 0... .... .... = OFPPF_COPPER: False
.... .... .... .... ...0 .... .... .... = OFPPF_FIBER: False
.... .... .... .... ..0. .... .... .... = OFPPF_AUTONEG: False
.... .... .... .... .0.. .... .... .... = OFPPF_PAUSE: False
.... .... .... .... 0... .... .... .... = OFPPF_PAUSE_ASYM: False
Supported: 0x00000000
.... .... .... .... .... .... .... ...0 = OFPPF_10MB_HD: False
.... .... .... .... .... .... .... ..0. = OFPPF_10MB_FD: False
.... .... .... .... .... .... .... .0.. = OFPPF_100MB_HD: False
.... .... .... .... .... .... .... 0... = OFPPF_100MB_FD: False
.... .... .... .... .... .... ...0 .... = OFPPF_1GB_HD: False
.... .... .... .... .... .... ..0. .... = OFPPF_1GB_FD: False
.... .... .... .... .... .... .0.. .... = OFPPF_10_GB_FD: False
.... .... .... .... .... .... 0... .... = OFPPF_40GB_FD: False
.... .... .... .... .... ...0 .... .... = OFPPF_100GB_FD: False
.... .... .... .... .... ..0. .... .... = OFPPF_1TB_FD: False
.... .... .... .... .... .0.. .... .... = OFPPF_OTHER: False
.... .... .... .... .... 0... .... .... = OFPPF_COPPER: False
.... .... .... .... ...0 .... .... .... = OFPPF_FIBER: False
.... .... .... .... ..0. .... .... .... = OFPPF_AUTONEG: False
.... .... .... .... .0.. .... .... .... = OFPPF_PAUSE: False
.... .... .... .... 0... .... .... .... = OFPPF_PAUSE_ASYM: False
Peer: 0x00000000
.... .... .... .... .... .... .... ...0 = OFPPF_10MB_HD: False
.... .... .... .... .... .... .... ..0. = OFPPF_10MB_FD: False
.... .... .... .... .... .... .... .0.. = OFPPF_100MB_HD: False
.... .... .... .... .... .... .... 0... = OFPPF_100MB_FD: False
.... .... .... .... .... .... ...0 .... = OFPPF_1GB_HD: False
.... .... .... .... .... .... ..0. .... = OFPPF_1GB_FD: False
.... .... .... .... .... .... .0.. .... = OFPPF_10_GB_FD: False
.... .... .... .... .... .... 0... .... = OFPPF_40GB_FD: False
.... .... .... .... .... ...0 .... .... = OFPPF_100GB_FD: False
.... .... .... .... .... ..0. .... .... = OFPPF_1TB_FD: False
.... .... .... .... .... .0.. .... .... = OFPPF_OTHER: False
.... .... .... .... .... 0... .... .... = OFPPF_COPPER: False
.... .... .... .... ...0 .... .... .... = OFPPF_FIBER: False
.... .... .... .... ..0. .... .... .... = OFPPF_AUTONEG: False
.... .... .... .... .0.. .... .... .... = OFPPF_PAUSE: False
.... .... .... .... 0... .... .... .... = OFPPF_PAUSE_ASYM: False
Curr speed: 10000000
Max speed: 0