-
Notifications
You must be signed in to change notification settings - Fork 34
/
of_sw_tutorial.py
239 lines (205 loc) · 9.12 KB
/
of_sw_tutorial.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#!/usr/bin/python
# Copyright 2012 James McCauley, William Yu
#
# This file is part of POX.
#
# POX is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# POX is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with POX. If not, see <http://www.gnu.org/licenses/>.
#
"""
This is a demonstration file that has various switch implementations.
The first example is a basic "all match" switch followed by a
destination match, pair match then finally a more ideal pair match
switch.
Mininet: sudo mn --topo single,3 --mac --switch ovsk --controller remote
Command Line: ./pox.py log.level --DEBUG samples.of_sw_tutorial
"""
# These next two imports are common POX convention
from pox.core import core
import pox.openflow.libopenflow_01 as of
# Even a simple usage of the logger is much nicer than print!
log = core.getLogger()
# This table maps (switch,MAC-addr) pairs to the port on 'switch' at
# which we last saw a packet *from* 'MAC-addr'.
# (In this case, we use a Connection object for the switch.)
table = {}
# Method for just sending a packet to any port (broadcast by default)
def send_packet (event, dst_port = of.OFPP_ALL):
msg = of.ofp_packet_out(in_port=event.ofp.in_port)
if event.ofp.buffer_id != -1 and event.ofp.buffer_id is not None:
# We got a buffer ID from the switch; use that
msg.buffer_id = event.ofp.buffer_id
else:
# No buffer ID from switch -- we got the raw data
if event.ofp.data:
# No raw_data specified -- nothing to send!
return
msg.data = event.ofp.data
msg.actions.append(of.ofp_action_output(port = dst_port))
event.connection.send(msg)
# DUMB HUB Implementation
# This is an implementation of a broadcast hub but all packets go
# to the controller since no flows are installed.
def _handle_dumbhub_packetin (event):
# Just send an instruction to the switch to send packet to all ports
packet = event.parsed
send_packet(event, of.OFPP_ALL)
log.debug("Broadcasting %s.%i -> %s.%i" %
(packet.src, event.ofp.in_port, packet.dst, of.OFPP_ALL))
# PAIR-WISE MATCHING HUB Implementation
# This is an implementation of a broadcast hub with flows installed.
def _handle_pairhub_packetin (event):
packet = event.parsed
# Create flow that simply broadcasts any packet received
msg = of.ofp_flow_mod()
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.match.dl_src = packet.src
msg.match.dl_dst = packet.dst
msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL))
event.connection.send(msg)
log.debug("Installing %s.%i -> %s.%i" %
(packet.src, event.ofp.in_port, packet.dst, of.OFPP_ALL))
# LAZY HUB Implementation (How hubs typically are)
# This is an implementation of a broadcast hub with flows installed.
def _handle_lazyhub_packetin (event):
packet = event.parsed
# Create flow that simply broadcasts any packet received
msg = of.ofp_flow_mod()
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL))
event.connection.send(msg)
log.debug("Installing %s.%i -> %s.%i" %
("ff:ff:ff:ff:ff:ff", event.ofp.in_port, "ff:ff:ff:ff:ff:ff",
of.OFPP_ALL))
# BAD SWITCH Implementation
# This is an obvious but problematic implementation of switch that
# routes based on destination MAC addresses.
def _handle_badswitch_packetin (event):
packet = event.parsed
# Learn the source and fill up routing table
table[(event.connection,packet.src)] = event.port
# install appropriate flow rule when learned
msg = of.ofp_flow_mod()
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.match.dl_dst = packet.src
msg.actions.append(of.ofp_action_output(port = event.port))
event.connection.send(msg)
# determine if appropriate destination route is available
dst_port = table.get((event.connection,packet.dst))
log.debug("Installing %s.%i -> %s.%i" %
("ff:ff:ff:ff:ff:ff", event.ofp.in_port, packet.src, event.port))
if dst_port is None:
# We don't know where the destination is yet. So, we'll just
# send the packet out all ports (except the one it came in on!)
# and hope the destination is out there somewhere. :)
# To send out all ports, we can use either of the special ports
# OFPP_FLOOD or OFPP_ALL. We'd like to just use OFPP_FLOOD,
# but it's not clear if all switches support this. :(
send_packet(event, of.OFPP_ALL)
log.debug("Broadcasting %s.%i -> %s.%i" %
(packet.src, event.ofp.in_port, packet.dst, of.OFPP_ALL))
else:
# This is the packet that just came in -- we want send the packet
# if we know the destination.
send_packet(event, dst_port)
log.debug("Sending %s.%i -> %s.%i" %
(packet.src, event.ofp.in_port, packet.dst, dst_port))
# PAIR-WISE MATCH SWITCH Implementation
# This is an implementation of an pair match switch. This only matches
# source and destination MAC addresses. Whenever a new source
# destination MAC address is detected it then add a new flow
# identifying the source destination pair. The routing table is updated
# using the detected destination MAC address to the destination port.
def _handle_pairswitch_packetin (event):
packet = event.parsed
# Learn the source and fill up routing table
table[(event.connection,packet.src)] = event.port
dst_port = table.get((event.connection,packet.dst))
if dst_port is None:
# We don't know where the destination is yet. So, we'll just
# send the packet out all ports (except the one it came in on!)
# and hope the destination is out there somewhere. :)
# To send out all ports, we can use either of the special ports
# OFPP_FLOOD or OFPP_ALL. We'd like to just use OFPP_FLOOD,
# but it's not clear if all switches support this. :(
send_packet(event, of.OFPP_ALL)
log.debug("Broadcasting %s.%i -> %s.%i" %
(packet.src, event.ofp.in_port, packet.dst, of.OFPP_ALL))
else:
# This is the packet that just came in -- we want to
# install the rule and also resend the packet.
msg = of.ofp_flow_mod()
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.match.dl_src = packet.src
msg.match.dl_dst = packet.dst
msg.actions.append(of.ofp_action_output(port = dst_port))
event.connection.send(msg)
log.debug("Installing %s.%i -> %s.%i" %
(packet.src, event.ofp.in_port, packet.dst, dst_port))
# SMARTER PAIR-WISE MATCH SWITCH Implementation
# This is an implementation of an ideal pair switch. This optimizes the
# previous example by adding both direction in one entry.
def _handle_idealpairswitch_packetin (event):
packet = event.parsed
# Learn the source and fill up routing table
table[(event.connection,packet.src)] = event.port
dst_port = table.get((event.connection,packet.dst))
if dst_port is None:
# We don't know where the destination is yet. So, we'll just
# send the packet out all ports (except the one it came in on!)
# and hope the destination is out there somewhere. :)
# To send out all ports, we can use either of the special ports
# OFPP_FLOOD or OFPP_ALL. We'd like to just use OFPP_FLOOD,
# but it's not clear if all switches support this. :(
send_packet(event, of.OFPP_ALL)
log.debug("Broadcasting %s.%i -> %s.%i" %
(packet.src, event.ofp.in_port, packet.dst, of.OFPP_ALL))
else:
# Since we know the switch ports for both the source and dest
# MACs, we can install rules for both directions.
msg = of.ofp_flow_mod()
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.match.dl_dst = packet.src
msg.match.dl_src = packet.dst
msg.actions.append(of.ofp_action_output(port = event.port))
event.connection.send(msg)
# This is the packet that just came in -- we want to
# install the rule and also resend the packet.
msg = of.ofp_flow_mod()
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.match.dl_src = packet.src
msg.match.dl_dst = packet.dst
msg.actions.append(of.ofp_action_output(port = dst_port))
event.connection.send(msg)
log.debug("Installing %s.%i -> %s.%i AND %s.%i -> %s.%i" %
(packet.dst, dst_port, packet.src, event.ofp.in_port,
packet.src, event.ofp.in_port, packet.dst, dst_port))
# function that is invoked upon load to ensure that listeners are
# registered appropriately. Uncomment the hub/switch you would like
# to test. Only one at a time please.
def launch ():
#core.openflow.addListenerByName("PacketIn", _handle_dumbhub_packetin)
#core.openflow.addListenerByName("PacketIn", _handle_pairhub_packetin)
#core.openflow.addListenerByName("PacketIn", _handle_lazyhub_packetin)
#core.openflow.addListenerByName("PacketIn", _handle_badswitch_packetin)
#core.openflow.addListenerByName("PacketIn", _handle_pairswitch_packetin)
core.openflow.addListenerByName("PacketIn",
_handle_idealpairswitch_packetin)
log.info("Switch Tutorial is running.")