blob: a410aaf6574203c362db083ee1e5a9fe89620dc0 [file] [log] [blame]
Dan Talayco34089522010-02-07 23:07:41 -08001"""
2OpenFlow Test Framework
3
Dan Talayco3087a462010-02-13 14:01:47 -08004DataPlane and DataPlanePort classes
Dan Talayco34089522010-02-07 23:07:41 -08005
6Provide the interface to the control the set of ports being used
7to stimulate the switch under test.
8
9See the class dataplaneport for more details. This class wraps
Dan Talaycoe226eb12010-02-18 23:06:30 -080010a set of those objects allowing general calls and parsing
Dan Talayco34089522010-02-07 23:07:41 -080011configuration.
12
Dan Talayco3087a462010-02-13 14:01:47 -080013@todo Add "filters" for matching packets. Actions supported
14for filters should include a callback or a counter
Dan Talayco34089522010-02-07 23:07:41 -080015"""
16
Dan Talayco3087a462010-02-13 14:01:47 -080017import sys
18import os
19import socket
20import time
Dan Talaycod7e2dbe2010-02-13 21:51:15 -080021import netutils
Dan Talayco3087a462010-02-13 14:01:47 -080022from threading import Thread
23from threading import Lock
Dan Talaycoe226eb12010-02-18 23:06:30 -080024from threading import Condition
Dan Talayco710438c2010-02-18 15:16:07 -080025import select
Dan Talayco48370102010-03-03 15:17:33 -080026import logging
27from oft_assert import oft_assert
Rich Lanedb9d8662012-07-26 18:04:24 -070028from ofutils import *
Dan Talayco3087a462010-02-13 14:01:47 -080029
Rich Laneb42a31c2012-10-05 17:54:17 -070030have_pypcap = False
31try:
32 import pcap
Ed Swierkab0bab32012-11-30 13:31:00 -080033 if hasattr(pcap, "pcap"):
34 # the incompatible pylibpcap library masquerades as pcap
35 have_pypcap = True
Rich Laneb42a31c2012-10-05 17:54:17 -070036except:
37 pass
38
Dan Talayco48370102010-03-03 15:17:33 -080039##@todo Find a better home for these identifiers (dataplane)
40RCV_SIZE_DEFAULT = 4096
Dan Talayco3087a462010-02-13 14:01:47 -080041ETH_P_ALL = 0x03
42RCV_TIMEOUT = 10000
Dan Talayco3087a462010-02-13 14:01:47 -080043
Ed Swierk506614a2012-03-29 08:16:59 -070044def match_exp_pkt(exp_pkt, pkt):
45 """
46 Compare the string value of pkt with the string value of exp_pkt,
47 and return True iff they are identical. If the length of exp_pkt is
48 less than the minimum Ethernet frame size (60 bytes), then padding
49 bytes in pkt are ignored.
50 """
51 e = str(exp_pkt)
52 p = str(pkt)
53 if len(e) < 60:
54 p = p[:len(e)]
55 return e == p
56
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -070057
Dan Talayco3087a462010-02-13 14:01:47 -080058class DataPlanePort(Thread):
59 """
60 Class defining a port monitoring object.
61
62 Control a dataplane port connected to the switch under test.
63 Creates a promiscuous socket on a physical interface.
64 Queues the packets received on that interface with time stamps.
65 Inherits from Thread class as meant to run in background. Also
66 supports polling.
Dan Talaycoe226eb12010-02-18 23:06:30 -080067
68 Currently assumes a controlling 'parent' which maintains a
69 common Lock object and a total packet-pending count. May want
70 to decouple that some day.
Dan Talayco3087a462010-02-13 14:01:47 -080071 """
72
Dan Talaycoe226eb12010-02-18 23:06:30 -080073 def __init__(self, interface_name, port_number, parent, max_pkts=1024):
Dan Talayco3087a462010-02-13 14:01:47 -080074 """
75 Set up a port monitor object
76 @param interface_name The name of the physical interface like eth1
Dan Talayco4d065972010-02-18 23:11:32 -080077 @param port_number The port number associated with this port
Dan Talaycoe226eb12010-02-18 23:06:30 -080078 @param parent The controlling dataplane object; for pkt wait CV
Dan Talayco3087a462010-02-13 14:01:47 -080079 @param max_pkts Maximum number of pkts to keep in queue
80 """
81 Thread.__init__(self)
82 self.interface_name = interface_name
83 self.max_pkts = max_pkts
Dan Talayco3087a462010-02-13 14:01:47 -080084 self.packets_total = 0
85 self.packets = []
Dan Talayco1b3f6902010-02-15 14:14:19 -080086 self.packets_discarded = 0
Dan Talaycoe226eb12010-02-18 23:06:30 -080087 self.port_number = port_number
Dan Talayco48370102010-03-03 15:17:33 -080088 logname = "dp-" + interface_name
89 self.logger = logging.getLogger(logname)
Dan Talayco0db53eb2010-03-10 14:00:02 -080090 try:
91 self.socket = self.interface_open(interface_name)
92 except:
93 self.logger.info("Could not open socket")
Rich Laneb42a31c2012-10-05 17:54:17 -070094 raise
95 self.logger.info("Opened port monitor (class %s)", type(self).__name__)
Dan Talaycoe226eb12010-02-18 23:06:30 -080096 self.parent = parent
Rich Laned7d32922012-12-24 15:03:20 -080097 self.killed = False
Dan Talayco1b3f6902010-02-15 14:14:19 -080098
Rich Lane5b5da2d2012-12-22 19:56:32 -080099 # Used to wake up the event loop in kill()
100 self.waker = EventDescriptor()
101
Dan Talayco3087a462010-02-13 14:01:47 -0800102 def interface_open(self, interface_name):
103 """
104 Open a socket in a promiscuous mode for a data connection.
105 @param interface_name port name as a string such as 'eth1'
106 @retval s socket
107 """
Dan Talaycoe226eb12010-02-18 23:06:30 -0800108 s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
Dan Talayco3087a462010-02-13 14:01:47 -0800109 socket.htons(ETH_P_ALL))
110 s.bind((interface_name, 0))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800111 netutils.set_promisc(s, interface_name)
Dan Talayco3087a462010-02-13 14:01:47 -0800112 s.settimeout(RCV_TIMEOUT)
113 return s
114
Dan Talayco3087a462010-02-13 14:01:47 -0800115 def run(self):
116 """
117 Activity function for class
118 """
Rich Lane5b5da2d2012-12-22 19:56:32 -0800119 self.socs = [self.socket, self.waker]
Dan Talayco710438c2010-02-18 15:16:07 -0800120 error_warned = False # Have we warned about error?
Rich Laned7d32922012-12-24 15:03:20 -0800121 while not self.killed:
Dan Talayco3087a462010-02-13 14:01:47 -0800122 try:
Dan Talayco710438c2010-02-18 15:16:07 -0800123 sel_in, sel_out, sel_err = \
124 select.select(self.socs, [], [], 1)
125 except:
126 print sys.exc_info()
Dan Talayco48370102010-03-03 15:17:33 -0800127 self.logger.error("Select error, exiting")
128 break
Dan Talayco710438c2010-02-18 15:16:07 -0800129
Dan Talayco48370102010-03-03 15:17:33 -0800130 if (sel_in is None) or (len(sel_in) == 0):
Dan Talayco710438c2010-02-18 15:16:07 -0800131 continue
132
Rich Lane5b5da2d2012-12-22 19:56:32 -0800133 if self.waker in sel_in:
134 self.waker.wait()
135 continue
136
Dan Talayco710438c2010-02-18 15:16:07 -0800137 try:
Dan Talayco48370102010-03-03 15:17:33 -0800138 rcvmsg = self.socket.recv(RCV_SIZE_DEFAULT)
Dan Talayco3087a462010-02-13 14:01:47 -0800139 except socket.error:
Dan Talayco710438c2010-02-18 15:16:07 -0800140 if not error_warned:
Dan Talayco48370102010-03-03 15:17:33 -0800141 self.logger.info("Socket error on recv")
Dan Talayco710438c2010-02-18 15:16:07 -0800142 error_warned = True
Dan Talayco1b3f6902010-02-15 14:14:19 -0800143 continue
Dan Talayco710438c2010-02-18 15:16:07 -0800144
Dan Talayco1b3f6902010-02-15 14:14:19 -0800145 if len(rcvmsg) == 0:
Dan Talayco48370102010-03-03 15:17:33 -0800146 self.logger.info("Zero len pkt rcvd")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800147 self.kill()
Dan Talayco3087a462010-02-13 14:01:47 -0800148 break
149
Rich Laned2e93aa2012-12-05 17:55:46 -0800150 rcvtime = time.time()
Dan Talayco48370102010-03-03 15:17:33 -0800151 self.logger.debug("Pkt len " + str(len(rcvmsg)) +
Ed Swierk4e200302012-03-19 14:53:31 -0700152 " in at " + str(rcvtime) + " on port " +
153 str(self.port_number))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800154
Dan Talaycoe226eb12010-02-18 23:06:30 -0800155 # Enqueue packet
Rich Lanedb9d8662012-07-26 18:04:24 -0700156 with self.parent.pkt_sync:
157 if len(self.packets) >= self.max_pkts:
158 # Queue full, throw away oldest
159 self.packets.pop(0)
160 self.packets_discarded += 1
161 self.logger.debug("Discarding oldest packet to make room")
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700162 self.packets.append((rcvmsg, rcvtime))
163 self.packets_total += 1
Rich Lanedb9d8662012-07-26 18:04:24 -0700164 self.parent.pkt_sync.notify_all()
Dan Talayco1b3f6902010-02-15 14:14:19 -0800165
Rich Lanedb9d8662012-07-26 18:04:24 -0700166 self.logger.info("Thread exit")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800167
168 def kill(self):
169 """
170 Terminate the running thread
171 """
Dan Talayco48370102010-03-03 15:17:33 -0800172 self.logger.debug("Port monitor kill")
Rich Laned7d32922012-12-24 15:03:20 -0800173 self.killed = True
Rich Lane5b5da2d2012-12-22 19:56:32 -0800174 self.waker.notify()
Dan Talayco1b3f6902010-02-15 14:14:19 -0800175 try:
176 self.socket.close()
177 except:
Dan Talayco48370102010-03-03 15:17:33 -0800178 self.logger.info("Ignoring dataplane soc shutdown error")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800179
Dan Talayco3087a462010-02-13 14:01:47 -0800180 def timestamp_head(self):
181 """
182 Return the timestamp of the head of queue or None if empty
183 """
Dan Talayco710438c2010-02-18 15:16:07 -0800184 rv = None
Dan Talaycoe226eb12010-02-18 23:06:30 -0800185 try:
Dan Talayco710438c2010-02-18 15:16:07 -0800186 rv = self.packets[0][1]
Dan Talaycoe226eb12010-02-18 23:06:30 -0800187 except:
188 rv = None
Dan Talayco710438c2010-02-18 15:16:07 -0800189 return rv
Dan Talayco3087a462010-02-13 14:01:47 -0800190
191 def flush(self):
192 """
193 Clear the packet queue
194 """
Rich Lanedb9d8662012-07-26 18:04:24 -0700195 with self.parent.pkt_sync:
196 self.packets_discarded += len(self.packets)
197 self.packets = []
Dan Talayco3087a462010-02-13 14:01:47 -0800198
199 def send(self, packet):
200 """
201 Send a packet to the dataplane port
202 @param packet The packet data to send to the port
203 @retval The number of bytes sent
204 """
205 return self.socket.send(packet)
206
Dan Talayco3087a462010-02-13 14:01:47 -0800207 def register(self, handler):
208 """
209 Register a callback function to receive packets from this
Dan Talaycoe226eb12010-02-18 23:06:30 -0800210 port. The callback will be passed the packet, the
211 interface name and the port number (if set) on which the
Dan Talayco3087a462010-02-13 14:01:47 -0800212 packet was received.
213
214 To be implemented
215 """
216 pass
217
Dan Talayco1b3f6902010-02-15 14:14:19 -0800218 def show(self, prefix=''):
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500219
Dan Talayco1b3f6902010-02-15 14:14:19 -0800220 print prefix + "Name: " + self.interface_name
Dan Talayco710438c2010-02-18 15:16:07 -0800221 print prefix + "Pkts pending: " + str(len(self.packets))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800222 print prefix + "Pkts total: " + str(self.packets_total)
223 print prefix + "socket: " + str(self.socket)
Dan Talaycoe226eb12010-02-18 23:06:30 -0800224
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500225
226 def port_down(self,port_number,config):
227
228 """
229 Grabs a port from the dataplane ports and brings it down by
230 shutting the corresponding interface
231 @port_number The port number which has brought to be down
232 @interface_name The interface corresponding to the port that needs to
233 be brought down
234
235 """
236 interface_name = config["port_map"].get(port_number)
237 cmd = 'ifdown '+ interface_name
238 os.system(cmd)
239
240 def port_up(self,port_number,config):
241
242 """
243 Grabs a port from the dataplane ports and brings it up by
244 starting up the corresponding interface
245 @port_number The port number which has to brought up
246 @interface_name The interface corresponding to the port that has to
247 be brought up
248
249 """
250 interface_name = config["port_map"].get(port_number)
251 cmd = 'ifup '+ interface_name
252 os.system(cmd)
253
254
Rich Laneb42a31c2012-10-05 17:54:17 -0700255class DataPlanePortPcap(DataPlanePort):
256 """
257 Alternate port implementation using libpcap. This is required for recent
258 versions of Linux (such as Linux 3.2 included in Ubuntu 12.04) which
259 offload the VLAN tag, so it isn't in the data returned from a read on a raw
260 socket. libpcap understands how to read the VLAN tag from the kernel.
261 """
262
263 def __init__(self, interface_name, port_number, parent, max_pkts=1024):
264 DataPlanePort.__init__(self, interface_name, port_number, parent, max_pkts)
265
266 def interface_open(self, interface_name):
267 """
268 Open a PCAP interface.
269 """
270 self.pcap = pcap.pcap(interface_name)
271 self.pcap.setnonblock()
272 return self.pcap.fileno()
273
274 def run(self):
275 """
276 Activity function for class
277 """
Rich Laned7d32922012-12-24 15:03:20 -0800278 while not self.killed:
Rich Laneb42a31c2012-10-05 17:54:17 -0700279 try:
Rich Lane5b5da2d2012-12-22 19:56:32 -0800280 sel_in, sel_out, sel_err = select.select([self.socket, self.waker], [], [], 1)
Rich Laneb42a31c2012-10-05 17:54:17 -0700281 except:
282 print sys.exc_info()
283 self.logger.error("Select error, exiting")
284 break
285
Rich Laneb42a31c2012-10-05 17:54:17 -0700286 if (sel_in is None) or (len(sel_in) == 0):
287 continue
288
Rich Lane5b5da2d2012-12-22 19:56:32 -0800289 if self.waker in sel_in:
290 self.waker.wait()
291 continue
292
Rich Laneb42a31c2012-10-05 17:54:17 -0700293 # Enqueue packet
294 with self.parent.pkt_sync:
295 for (timestamp, rcvmsg) in self.pcap.readpkts():
Rich Laneb42a31c2012-10-05 17:54:17 -0700296 self.logger.debug("Pkt len " + str(len(rcvmsg)) +
Rich Laned2e93aa2012-12-05 17:55:46 -0800297 " in at " + str(timestamp) + " on port " +
Rich Laneb42a31c2012-10-05 17:54:17 -0700298 str(self.port_number))
299
300 if len(self.packets) >= self.max_pkts:
301 # Queue full, throw away oldest
302 self.packets.pop(0)
303 self.packets_discarded += 1
304 self.logger.debug("Discarding oldest packet to make room")
Rich Laned2e93aa2012-12-05 17:55:46 -0800305 self.packets.append((rcvmsg, timestamp))
Rich Laneb42a31c2012-10-05 17:54:17 -0700306 self.packets_total += 1
307 self.parent.pkt_sync.notify_all()
308
309 self.logger.info("Thread exit")
310
311 def kill(self):
312 """
313 Terminate the running thread
314 """
315 self.logger.debug("Port monitor kill")
Rich Laned7d32922012-12-24 15:03:20 -0800316 self.killed = True
Rich Lane5b5da2d2012-12-22 19:56:32 -0800317 self.waker.notify()
Rich Laneb42a31c2012-10-05 17:54:17 -0700318 # pcap object is closed on GC.
319
320 def send(self, packet):
321 """
322 Send a packet to the dataplane port
323 @param packet The packet data to send to the port
324 @retval The number of bytes sent
325 """
326 return self.pcap.inject(packet, len(packet))
Dan Talayco34089522010-02-07 23:07:41 -0800327
328class DataPlane:
329 """
330 Class defining access primitives to the data plane
331 Controls a list of DataPlanePort objects
332 """
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700333 def __init__(self, config=None):
Dan Talayco34089522010-02-07 23:07:41 -0800334 self.port_list = {}
Dan Talaycoe226eb12010-02-18 23:06:30 -0800335 # pkt_sync serves double duty as a regular top level lock and
336 # as a condition variable
337 self.pkt_sync = Condition()
338
339 # These are used to signal async pkt arrival for polling
340 self.want_pkt = False
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700341 self.exp_pkt = None
Dan Talaycoe226eb12010-02-18 23:06:30 -0800342 self.want_pkt_port = None # What port required (or None)
343 self.got_pkt_port = None # On what port received?
344 self.packets_pending = 0 # Total pkts in all port queues
Dan Talayco48370102010-03-03 15:17:33 -0800345 self.logger = logging.getLogger("dataplane")
Dan Talayco34089522010-02-07 23:07:41 -0800346
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700347 if config is None:
348 self.config = {}
349 else:
350 self.config = config;
351
352 ############################################################
353 #
354 # We use the DataPlanePort class defined here by
355 # default for all port traffic:
356 #
Rich Laneb42a31c2012-10-05 17:54:17 -0700357 if have_pypcap:
358 self.dppclass = DataPlanePortPcap
359 else:
360 self.logger.warning("Missing pypcap, VLAN tests may fail. See README for installation instructions.")
361 self.dppclass = DataPlanePort
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700362
363 ############################################################
364 #
365 # The platform/config can provide a custom DataPlanePort class
366 # here if you have a custom implementation with different
367 # behavior.
368 #
369 # Set config.dataplane.portclass = MyDataPlanePortClass
370 # where MyDataPlanePortClass has the same interface as the class
371 # DataPlanePort defined here.
372 #
373 if "dataplane" in self.config:
374 if "portclass" in self.config["dataplane"]:
375 self.dppclass = self.config["dataplane"]["portclass"]
376
377 if self.dppclass == None:
378 raise Exception("Problem determining DataPlanePort class.")
379
380
Dan Talayco34089522010-02-07 23:07:41 -0800381 def port_add(self, interface_name, port_number):
382 """
383 Add a port to the dataplane
384 TBD: Max packets for queue?
385 @param interface_name The name of the physical interface like eth1
386 @param port_number The port number used to refer to the port
387 """
Dan Talaycoe226eb12010-02-18 23:06:30 -0800388
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700389 self.port_list[port_number] = self.dppclass(interface_name,
390 port_number, self);
391
Dan Talayco34089522010-02-07 23:07:41 -0800392 self.port_list[port_number].start()
393
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700394
395
Dan Talayco34089522010-02-07 23:07:41 -0800396 def send(self, port_number, packet):
397 """
398 Send a packet to the given port
399 @param port_number The port to send the data to
400 @param packet Raw packet data to send to port
401 """
Dan Talayco11c26e72010-03-07 22:03:57 -0800402 self.logger.debug("Sending %d bytes to port %d" %
403 (len(packet), port_number))
Dan Talayco34089522010-02-07 23:07:41 -0800404 bytes = self.port_list[port_number].send(packet)
405 if bytes != len(packet):
Dan Talayco48370102010-03-03 15:17:33 -0800406 self.logger.error("Unhandled send error, length mismatch %d != %d" %
Dan Talayco1b3f6902010-02-15 14:14:19 -0800407 (bytes, len(packet)))
Dan Talayco34089522010-02-07 23:07:41 -0800408 return bytes
409
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500410
411
412
Dan Talayco34089522010-02-07 23:07:41 -0800413 def flood(self, packet):
414 """
415 Send a packet to all ports
416 @param packet Raw packet data to send to port
417 """
418 for port_number in self.port_list.keys():
419 bytes = self.port_list[port_number].send(packet)
420 if bytes != len(packet):
Dan Talayco48370102010-03-03 15:17:33 -0800421 self.logger.error("Unhandled send error" +
Dan Talayco1b3f6902010-02-15 14:14:19 -0800422 ", port %d, length mismatch %d != %d" %
423 (port_number, bytes, len(packet)))
Dan Talayco34089522010-02-07 23:07:41 -0800424
Rich Lanedb9d8662012-07-26 18:04:24 -0700425 # Returns the port with the oldest packet, or None if no packets are queued.
426 def oldest_port(self):
427 min_port = None
428 min_time = float('inf')
429 for port in self.port_list.values():
430 ptime = port.timestamp_head()
431 if ptime and ptime < min_time:
432 min_time = ptime
433 min_port = port
434 return min_port
435
436 # Dequeues and yields packets in the order they were received.
437 # Yields (port, packet, received time).
438 # If port_number is not specified yields packets from all ports.
439 def packets(self, port_number=None):
440 while True:
441 if port_number == None:
442 port = self.oldest_port()
443 else:
444 port = self.port_list[port_number]
445
446 if port == None or len(port.packets) == 0:
447 self.logger.debug("Out of packets for port %s" % str(port_number))
448 # Out of packets
449 break
450
451 pkt, time = port.packets.pop(0)
452 yield (port, pkt, time)
453
Rich Lane8806bc42012-07-26 19:18:37 -0700454 def poll(self, port_number=None, timeout=-1, exp_pkt=None):
Dan Talaycoe226eb12010-02-18 23:06:30 -0800455 """
456 Poll one or all dataplane ports for a packet
457
458 If port_number is given, get the oldest packet from that port.
459 Otherwise, find the port with the oldest packet and return
460 that packet.
Dan Talayco1729fdb2012-05-03 09:35:56 -0700461
462 If exp_pkt is true, discard all packets until that one is found
463
Dan Talaycoe226eb12010-02-18 23:06:30 -0800464 @param port_number If set, get packet from this port
Dan Talayco11c26e72010-03-07 22:03:57 -0800465 @param timeout If positive and no packet is available, block
Dan Talaycoe226eb12010-02-18 23:06:30 -0800466 until a packet is received or for this many seconds
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700467 @param exp_pkt If not None, look for this packet and ignore any
Dan Talayco1729fdb2012-05-03 09:35:56 -0700468 others received. Note that if port_number is None, all packets
469 from all ports will be discarded until the exp_pkt is found
Dan Talaycoe226eb12010-02-18 23:06:30 -0800470 @return The triple port_number, packet, pkt_time where packet
471 is received from port_number at time pkt_time. If a timeout
472 occurs, return None, None, None
473 """
474
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700475 if exp_pkt and not port_number:
Dan Talayco1729fdb2012-05-03 09:35:56 -0700476 self.logger.warn("Dataplane poll with exp_pkt but no port number")
477
Rich Lanedb9d8662012-07-26 18:04:24 -0700478 # Retrieve the packet. Returns (port number, packet, time).
479 def grab():
480 self.logger.debug("Grabbing packet")
481 for (port, pkt, time) in self.packets(port_number):
482 self.logger.debug("Checking packet from port %d" % port.port_number)
Dan Talayco1729fdb2012-05-03 09:35:56 -0700483 if not exp_pkt or match_exp_pkt(exp_pkt, pkt):
Rich Lanedb9d8662012-07-26 18:04:24 -0700484 return (port, pkt, time)
485 self.logger.debug("Did not find packet")
486 return None
Dan Talaycoe226eb12010-02-18 23:06:30 -0800487
Rich Lanedb9d8662012-07-26 18:04:24 -0700488 with self.pkt_sync:
489 ret = timed_wait(self.pkt_sync, grab, timeout=timeout)
Dan Talayco34089522010-02-07 23:07:41 -0800490
Rich Lanedb9d8662012-07-26 18:04:24 -0700491 if ret != None:
492 (port, pkt, time) = ret
493 return (port.port_number, pkt, time)
494 else:
495 self.logger.debug("Poll time out, no packet from " + str(port_number))
496 return (None, None, None)
Dan Talayco34089522010-02-07 23:07:41 -0800497
Dan Talayco48370102010-03-03 15:17:33 -0800498 def kill(self, join_threads=True):
Dan Talayco1b3f6902010-02-15 14:14:19 -0800499 """
500 Close all sockets for dataplane
Dan Talayco710438c2010-02-18 15:16:07 -0800501 @param join_threads If True call join on each thread
Dan Talayco1b3f6902010-02-15 14:14:19 -0800502 """
Dan Talayco34089522010-02-07 23:07:41 -0800503 for port_number in self.port_list.keys():
504 self.port_list[port_number].kill()
Rich Lane4d46dbd2012-12-22 19:26:19 -0800505
506 if join_threads:
507 for port_number in self.port_list.keys():
Dan Talayco48370102010-03-03 15:17:33 -0800508 self.logger.debug("Joining " + str(port_number))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800509 self.port_list[port_number].join()
Dan Talayco34089522010-02-07 23:07:41 -0800510
Rich Lanee7b0ecb2012-12-26 10:01:01 -0800511 self.port_list = None
512
Dan Talayco48370102010-03-03 15:17:33 -0800513 self.logger.info("DataPlane shutdown")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800514
515 def show(self, prefix=''):
516 print prefix + "Dataplane Controller"
Dan Talaycoe226eb12010-02-18 23:06:30 -0800517 print prefix + "Packets pending" + str(self.packets_pending)
Dan Talayco1b3f6902010-02-15 14:14:19 -0800518 for pnum, port in self.port_list.items():
519 print prefix + "OpenFlow Port Number " + str(pnum)
520 port.show(prefix + ' ')
521
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500522
523 def port_down(self,port_number):
524 """Brings the specified port down"""
525 self.port_list[port_number].port_down(port_number,self.config)
526
527
528 def port_up(self,port_number):
529 """Brings the specified port up"""
530 self.port_list[port_number].port_up(port_number,self.config)