-
Notifications
You must be signed in to change notification settings - Fork 1
/
port_stats.py
178 lines (138 loc) · 6.84 KB
/
port_stats.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
from pox.core import core
import pox.openflow.libopenflow_01 as of
from pox.lib.recoco import Timer
log = core.getLogger()
IDLE_TIMOUT = 5
HARD_TIMEOUT = 15
def launch ():
"""
Launch is the entry point of the module, much like __main__
"""
# Register the switch_component to the system
core.registerNew(SwitchComponent)
class SwitchComponent(object):
'''
The switch component is the handler of opendlow events for our
application
'''
def __init__(self):
log.info("Starting SwitchComponent")
# Make the switch component a listener to openflow events
core.openflow.addListeners(self)
def _handle_ConnectionUp(self, event):
log.info("Creating switch device on %s" % (event.connection,))
# Create a new Hub on the device having this connection
Switch(event.connection)
class Switch(object):
'''
The switch class is instantiated once for each openflow device
that connects to the switch component. The switch class tranforms
the said device to an ethernet learning switch
'''
# The connection to device object
connection = None
def __init__(self, connection):
'''
Create the Switch instance
'''
# Store the connection object in the instance
self.connection = connection
# The MAC table linking MAC addresses with ports
self.mac_table = {}
# Register to the connection to listen events from the device
# and pass them to the instance (self)
connection.addListeners(self)
# Register to the connection to listen for PortStartsReceived evetns
# These events will be handled by the "handle_port_stats" method
connection.addListenerByName("PortStatsReceived", self.handle_port_stats)
# Every x seconds call the "send_stats_request" method
Timer(10, self.send_stats_request, recurring = True)
def handle_port_stats(self, event):
########
# Log the packets in and packets out for each port
########
pass
def send_stats_request (self):
########
# Send a port stats request to the switch
########
pass
def _handle_PacketIn (self, event):
'''
Callback function that receives packet_in events and responds
to them. Packet in events are sent from the device and carry a
data packet that the device does not know what to do with
'''
# Extract the data packet from the packet in event
data = event.parsed
# Update the MAC table. The MAC address that is the source of
# the frame is served from the port where this packet originated
# We should store (or update) this relation
self.mac_table[data.src] = event.port
# We extract the destination MAC address from the data
dst = data.dst
if dst.is_multicast:
# If the destination MAC is a multicast address, send the
# frame out of all ports, like a hub
log.info("Received multicast from %s" % (self.connection,))
# Create a new flow_mod message
msg = of.ofp_flow_mod()
# Set the hard and idle timeouts to sane values
msg.idle_timeout = IDLE_TIMOUT
msg.hard_timeout = HARD_TIMEOUT
# Match the destination mac address that triggered this packet_in event
msg.match = of.ofp_match(dl_dst=dst)
# Flood the packet to all ports (but the incoming)
msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
# Set the buffer of the message that triggered the packet in event
# This way that message will be treated by the new flow and will
# not be lost
msg.buffer_id = event.ofp.buffer_id
# Send the message to the switch
self.connection.send(msg)
else:
if dst in self.mac_table:
# If the destination MAC address exists in the MAC table
# we will send the packet out from the port the MAC
# table has stored, unless it is the same as the
# incoming port
if event.port == self.mac_table[dst]:
# If the source port is the same as the destination
# port do nothing (efectively drop the packet)
pass
else:
# If the source port is different than the destinationport
# create a new flow matching the port-mac_src-mac_dst and
# push it to the device
log.info("Received unicast from %s with known destination %s" % (self.connection, dst))
# Create a new flow_mod message
msg = of.ofp_flow_mod()
# Match the destination MAC address with the one received in the message carried by the packet_in
msg.match = of.ofp_match(dl_dst=data.dst)
# Set timeouts to sane values
msg.idle_timeout = IDLE_TIMOUT
msg.hard_timeout = HARD_TIMEOUT
# Send this message to the port indicated by the MAC table
msg.actions.append(of.ofp_action_output(port = self.mac_table[dst]))
# Set the buffer of the message that triggered the packet in event
# This way that message will be treated by the new flow and will
# not be lost
msg.buffer_id = event.ofp.buffer_id
# Send the message to the switch
self.connection.send(msg)
else:
# If the destination MAC address is not in the MAC table
# Flood the message to all ports excpet the incoming one
# Hopefully the destination will answer and eventually his
# port will become known
log.info("Received unicast from %s with uknown destination %s" % (self.connection, dst))
# Create a new packet_out message
msg = of.ofp_packet_out()
# Indicate the port this packet came from
msg.in_port = event.port
# Set the action to flood the packet
msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
# Set the data to flood
msg.data = event.ofp
# Send the message to the switch
self.connection.send(msg)