-
Notifications
You must be signed in to change notification settings - Fork 18
/
MyTest.py
207 lines (180 loc) · 8.35 KB
/
MyTest.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
__author__ = 'ehsan'
from pox.core import core # Main POX object
from pox.lib.util import dpid_to_str
import pox.openflow.libopenflow_01 as of # OpenFlow 1.0 library
import time
import pox.lib.packet as pkt
#import pox.openflow as of
# Create a logger for this component
log = core.getLogger()
class MyTest (object):
def __init__(self, an_arg=1):
self.mode = an_arg
self.macToPort = {}
if self.mode == 1:
log.info("Mode is 1.")
elif self.mode == 2:
log.info("Mode is 2.")
core.openflow.addListeners(self)
def foo(self):
log.info("MyTest with " + str(self.mode))
"""
The object event has three properties:
.connection - A reference to the switch connection that caused the event
.dpid - The DPID of the switch that caused the event
.ofp - The openflow message tha caused the event to fire up (from libopenflow)
Note that libopenflow_01 is the place where you have all types of OF messages.
So right now a reference to the switch is copied to the object.
"""
def _handle_ConnectionUp(self, event):
log.info("Event DPID (i.e. DPID of the switch) : {0}\n".format(event.dpid) +
"Number of tables in the Switch : {0}\n".format(event.ofp.n_tables) +
"Number of buffers in the switch : {0}\n".format(event.ofp.n_buffers))
m = "Ports of switches: \n"
for p in event.ofp.ports:
m += "\t Port Name: {0}\n".format(p) + "\t\t Port Number = {0}\n".format(p.port_no) + \
"\t\t Hardware Address = {0}\n".format(p.hw_addr) + \
"\t\t Name = {0}\n".format(p.name) + \
"\t\t Configuration = {0}\n".format(p.config) + \
"\t\t State = {0}\n".format(p.state) + \
"\t\t Curr = {0}\n".format(p.curr) + \
"\t\t Advertised = {0}\n".format(p.advertised) + \
"\t\t Supported = {0}\n".format(p.supported) + \
"\t\t Peer = {0}\n".format(p.peer)
log.info(m)
self.conn = event.connection
def flood(self, event, message = None):
""" Floods the packet """
msg = of.ofp_packet_out()
if time.time() - self.conn.connect_time >= _flood_delay:
# Only flood if we've been connected for a little while...
if message is not None:
log.debug(message)
#log.debug("%i: flood %s -> %s", event.dpid,packet.src,packet.dst)
# OFPP_FLOOD is optional; on some switches you may need to change
# this to OFPP_ALL.
msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD))
else:
pass
msg.data = event.ofp
msg.in_port = event.port
self.conn.send(msg)
"""
:type event: event
:param event: Event that cause al these functions to execute
:type packet: event.parsed
:param packet: This is parsed packet
"""
def drop(self, event, packet, duration=None):
"""
Drops this packet and optionally installs a flow to continue
dropping similar ones for a while
"""
if duration is not None:
if not isinstance(duration, tuple):
duration = (duration,duration)
msg = of.ofp_flow_mod()
msg.match = of.ofp_match.from_packet(packet)
msg.idle_timeout = duration[0]
msg.hard_timeout = duration[1]
msg.buffer_id = event.ofp.buffer_id
self.conn.send(msg)
elif event.ofp.buffer_id is not None:
msg = of.ofp_packet_out()
msg.buffer_id = event.ofp.buffer_id
msg.in_port = event.port
self.conn.send(msg)
"""
:type event:event
:param event: The PacketIn event which caused _handle_PacketIn to be executed.
"""
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
""" Use source address and switch port to update address/port table """
log_msg = "Packet Received. \n\tSource of the packet -> {0}\n\tDestination of the packet -> {1}".format(packet.src, packet.dst)
self.macToPort[packet.src] = event.port
"""
If Ethertype is LLDP or the packet's destination address is a Bridge Filtered address?
Yes:
Drop packet -- don't forward link-local traffic (LLDP, 802.1x)
Note that EtherType is a two-octet field in an Ethernet frame. It is used to indicate which protocol is
encapsulated in the payload of an Ethernet Frame.
"""
if packet.type == packet.LLDP_TYPE or packet.dst.isBridgeFiltered():
log_msg += "\n\t\tPacket type is {0}. Drop the packet.".format(str(packet.type))
# drop() --> Note that this function is not implemented
self.drop(event=event, packet=packet)
return
""" Is destination multicast?
Yes:
Flood the packet
"""
if packet.dst.is_multicast:
log_msg += "\n\t\tPacket is multicast. Flood the packet."
# flood()
self.flood(event=event)
else:
"""
Port for destination address in our address/port table?
No:
Flood the packet
"""
if packet.dst not in self.macToPort:
log_msg += "\n\t\tPort for {0} is unknown so flood he packet. ".format(packet.dst)
self.flood(event=event, message="Port for %s unknown -- flooding " % (packet.dst, ))
else:
"""
Is output port the same as input port?
Yes:
Drop packet and similar ones for a while
"""
port = self.macToPort[packet.dst]
log_msg += "\n\t\tFor packets with dest = {0} use out port {1}".format(packet.dst, port)
if self.mode == 2:
if port == event.port:
log.warning("\n\t\tSame port for packet from {0} -> {1} on {2}.{3}. \n\t\tDrop the packet. Not "
"implemented".format(packet.src, packet.dst, dpid_to_str(event.dpid), port))
# drop(10) --> Note that this function is not implemented
return
log_msg += "\n\t\tInstalling a flow for destination {0} : Setting port to {1}".format(packet.dst, port)
flow_msg = of.ofp_flow_mod()
flow_msg.match = of.ofp_match.from_packet(packet=packet, in_port=event.port)
flow_msg.idle_timeout = 20
flow_msg.hard_timeout = 40
flow_msg.actions.append(of.ofp_action_output(port=port))
flow_msg.data = event.ofp
self.conn.send(flow_msg)
if self.mode == 1:
"""
This section tries to add rwo flow entries. It is only for learning purposes.
"""
pot = 0
if (packet.dst.toStr() == "00:00:00:00:00:02") == 0:
pot = 1
if (packet.dst.toStr() == "00:00:00:00:00:01") == 0:
pot = 2
if pot == 0:
log_msg += "\n\t\tThe function toStr() did not work."
log_msg += "\n\t\tInstalling a flow for destination {0}: Setting port to {1}".format(packet.dst.toStr(), pot)
flow_msg = of.ofp_flow_mod()
flow_msg.match = of.ofp_match.from_packet(packet=packet, in_port=event.port)
flow_msg.idle_timeout = 20
flow_msg.hard_timeout = 40
flow_msg.actions.append(of.ofp_action_output(port=pot))
flow_msg.data = event.ofp
self.conn.send(flow_msg)
log.info(log_msg)
def _handle_PacketOut (self, event):
log.info("Packet out was received")
def launch():
global _flood_delay
_flood_delay = 0
component = MyTest(1)
core.register("thing", component)
core.thing.foo() # prints "MyComponent with verbose: spam"