-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathof_switch_flow.py
234 lines (194 loc) · 7.67 KB
/
of_switch_flow.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
# Copyright 2012 James McCauley
#
# 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 component is for use with the OpenFlow tutorial.
It acts as a simple hub, but can be modified to act like an L2
learning switch.
It's quite similar to the one for NOX. Credit where credit due. :)
"""
from pox.core import core
import pox.openflow.libopenflow_01 as of
log = core.getLogger()
class Tutorial (object):
"""
A Tutorial object is created for each switch that connects.
A Connection object for that switch is passed to the __init__ function.
"""
def __init__ (self, connection):
# Keep track of the connection to the switch so that we can
# send it messages!
self.connection = connection
# This binds our PacketIn event listener
connection.addListeners(self)
# Use this table to keep track of which ethernet address is on
# which switch port (keys are MACs, values are ports).
self.mac_to_port = {}
def send_packet (self, buffer_id, raw_data, out_port, in_port):
"""
Sends a packet out of the specified switch port.
If buffer_id is a valid buffer on the switch, use that. Otherwise,
send the raw data in raw_data.
The "in_port" is the port number that packet arrived on. Use
OFPP_NONE if you're generating this packet.
"""
msg = of.ofp_packet_out()
msg.in_port = in_port
if buffer_id != -1 and buffer_id is not None:
# We got a buffer ID from the switch; use that
msg.buffer_id = buffer_id
else:
# No buffer ID from switch -- we got the raw data
if raw_data is None:
# No raw_data specified -- nothing to send!
return
msg.data = raw_data
# Add an action to send to the specified port
action = of.ofp_action_output(port = out_port)
msg.actions.append(action)
# Send message to switch
self.connection.send(msg)
def act_like_hub (self, packet, packet_in):
"""
Implement hub-like behavior -- send all packets to all ports besides
the input port.
"""
# We want to output to all ports -- we do that using the special
# OFPP_FLOOD port as the output port. (We could have also used
# OFPP_ALL.)
#self.send_packet(packet_in.buffer_id, packet_in.data,
# of.OFPP_FLOOD, packet_in.in_port)
log.debug("installing flow for %s.%i -> %s.%i" %
(packet.src, packet_in.in_port, packet.dst, of.OFPP_FLOOD))
msg = of.ofp_flow_mod()
msg.match = of.ofp_match.from_packet(packet)
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
msg.buffer_id = packet_in.buffer_id
self.connection.send(msg)
# Note that if we didn't get a valid buffer_id, a slightly better
# implementation would check that we got the full data before
# sending it (len(packet_in.data) should be == packet_in.total_len)).
def act_like_switch (self, packet, packet_in):
"""
Implement switch-like behavior.
"""
# Here's some psuedocode to start you off implementing a learning
# switch. You'll need to rewrite it as real Python code.
# Learn the port for the source MAC
self.mac_to_port[str(packet.src)] = packet_in.in_port
if str(packet.dst) in self.mac_to_port:
# Send packet out the associated port
#self.send_packet(packet_in.buffer_id, packet_in.data,
# self.mac_to_port[str(packet.dst)], packet_in.in_port)
# Once you have the above working, try pushing a flow entry
# instead of resending the packet (comment out the above and
# uncomment and complete the below.)
#log.debug("Installing flow: from " + str(packet_in.in_port))
# Maybe the log statement should have source/destination/port?
port = self.mac_to_port[str(packet.dst)]
log.debug("installing flow for %s.%i -> %s.%i" %
(packet.src, packet_in.in_port, packet.dst, port))
"""
# create new flow with match record set to match entire record
# what is wrong with this?
msg = of.ofp_flow_mod()
msg.match = of.ofp_match.from_packet(packet)
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = port))
msg.buffer_id = packet_in.buffer_id
self.connection.send(msg)
"""
"""
# create new flow with match record set to only match destination
# what is wrong with this?
msg = of.ofp_flow_mod()
msg.match.dl_dst = packet.dst
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = port))
msg.buffer_id = packet_in.buffer_id
self.connection.send(msg)
"""
# create new flow with match record set to only match destination
# what is wrong with this?
msg = of.ofp_flow_mod()
msg.match.dl_dst = packet.dst
msg.match.dl_src = packet.src
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = port))
msg.buffer_id = packet_in.buffer_id
self.connection.send(msg)
#msg = of.ofp_flow_mod()
#
## Set fields to match received packet
#msg.match = of.ofp_match.from_packet(packet)
#
#< Set other fields of flow_mod (timeouts? buffer_id?) >
#
#< Add an output action, and send -- similar to send_packet() >
#msg.in_port = packet_in.in_port
#if packet_in.buffer_id != -1 and packet_in.buffer_id is not None:
# We got a buffer ID from the switch; use that
# msg.buffer_id = packet_in.buffer_id
#else:
# No buffer ID from switch -- we got the raw data
# if packet_in.data is None:
# No raw_data specified -- nothing to send!
# return
# msg.data = packet_in.data
# Add an action to send to the specified port
#action = of.ofp_action_output(port = self.mac_to_port[str(packet.dst)])
#msg.actions.append(action)
else:
# Flood the packet out everything but the input port
# This part looks familiar, right?
self.send_packet(packet_in.buffer_id, packet_in.data,
of.OFPP_FLOOD, packet_in.in_port)
def _handle_PortStatus (self, event):
"""
Returns on change of port status
"""
if event.added:
log.debug("HW Address %s to port %d added (%d).",
event.ofp.desc.hw_addr, event.port, event.dpid)
elif event.deleted:
log.debug("Port %d deleted (%d).",
event.port, event.dpid)
def _handle_PacketIn (self, event):
"""
Handles packet in messages from the switch.
"""
packet = event.parsed # This is the parsed packet data.
if not packet.parsed:
log.warning("Ignoring incomplete packet")
return
packet_in = event.ofp # The actual ofp_packet_in message.
# Comment out the following line and uncomment the one after
# when starting the exercise.
#self.act_like_hub(packet, packet_in)
self.act_like_switch(packet, packet_in)
def launch ():
"""
Starts the component
"""
def start_switch (event):
log.debug("Controlling %s" % (event.connection,))
Tutorial(event.connection)
core.openflow.addListenerByName("ConnectionUp", start_switch)