blob: c8c59a46da2a25702ae1d90b44a728acb5f8e2ef [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
Dan Talayco1b3f6902010-02-15 14:14:19 -080097
Rich Lane5b5da2d2012-12-22 19:56:32 -080098 # Used to wake up the event loop in kill()
99 self.waker = EventDescriptor()
100
Dan Talayco3087a462010-02-13 14:01:47 -0800101 def interface_open(self, interface_name):
102 """
103 Open a socket in a promiscuous mode for a data connection.
104 @param interface_name port name as a string such as 'eth1'
105 @retval s socket
106 """
Dan Talaycoe226eb12010-02-18 23:06:30 -0800107 s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
Dan Talayco3087a462010-02-13 14:01:47 -0800108 socket.htons(ETH_P_ALL))
109 s.bind((interface_name, 0))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800110 netutils.set_promisc(s, interface_name)
Dan Talayco3087a462010-02-13 14:01:47 -0800111 s.settimeout(RCV_TIMEOUT)
112 return s
113
Dan Talayco3087a462010-02-13 14:01:47 -0800114 def run(self):
115 """
116 Activity function for class
117 """
118 self.running = True
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?
Dan Talayco3087a462010-02-13 14:01:47 -0800121 while self.running:
122 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
130 if not self.running:
131 break
132
Dan Talayco48370102010-03-03 15:17:33 -0800133 if (sel_in is None) or (len(sel_in) == 0):
Dan Talayco710438c2010-02-18 15:16:07 -0800134 continue
135
Rich Lane5b5da2d2012-12-22 19:56:32 -0800136 if self.waker in sel_in:
137 self.waker.wait()
138 continue
139
Dan Talayco710438c2010-02-18 15:16:07 -0800140 try:
Dan Talayco48370102010-03-03 15:17:33 -0800141 rcvmsg = self.socket.recv(RCV_SIZE_DEFAULT)
Dan Talayco3087a462010-02-13 14:01:47 -0800142 except socket.error:
Dan Talayco710438c2010-02-18 15:16:07 -0800143 if not error_warned:
Dan Talayco48370102010-03-03 15:17:33 -0800144 self.logger.info("Socket error on recv")
Dan Talayco710438c2010-02-18 15:16:07 -0800145 error_warned = True
Dan Talayco1b3f6902010-02-15 14:14:19 -0800146 continue
Dan Talayco710438c2010-02-18 15:16:07 -0800147
Dan Talayco1b3f6902010-02-15 14:14:19 -0800148 if len(rcvmsg) == 0:
Dan Talayco48370102010-03-03 15:17:33 -0800149 self.logger.info("Zero len pkt rcvd")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800150 self.kill()
Dan Talayco3087a462010-02-13 14:01:47 -0800151 break
152
Rich Laned2e93aa2012-12-05 17:55:46 -0800153 rcvtime = time.time()
Dan Talayco48370102010-03-03 15:17:33 -0800154 self.logger.debug("Pkt len " + str(len(rcvmsg)) +
Ed Swierk4e200302012-03-19 14:53:31 -0700155 " in at " + str(rcvtime) + " on port " +
156 str(self.port_number))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800157
Dan Talaycoe226eb12010-02-18 23:06:30 -0800158 # Enqueue packet
Rich Lanedb9d8662012-07-26 18:04:24 -0700159 with self.parent.pkt_sync:
160 if len(self.packets) >= self.max_pkts:
161 # Queue full, throw away oldest
162 self.packets.pop(0)
163 self.packets_discarded += 1
164 self.logger.debug("Discarding oldest packet to make room")
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700165 self.packets.append((rcvmsg, rcvtime))
166 self.packets_total += 1
Rich Lanedb9d8662012-07-26 18:04:24 -0700167 self.parent.pkt_sync.notify_all()
Dan Talayco1b3f6902010-02-15 14:14:19 -0800168
Rich Lanedb9d8662012-07-26 18:04:24 -0700169 self.logger.info("Thread exit")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800170
171 def kill(self):
172 """
173 Terminate the running thread
174 """
Dan Talayco48370102010-03-03 15:17:33 -0800175 self.logger.debug("Port monitor kill")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800176 self.running = False
Rich Lane5b5da2d2012-12-22 19:56:32 -0800177 self.waker.notify()
Dan Talayco1b3f6902010-02-15 14:14:19 -0800178 try:
179 self.socket.close()
180 except:
Dan Talayco48370102010-03-03 15:17:33 -0800181 self.logger.info("Ignoring dataplane soc shutdown error")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800182
Dan Talayco3087a462010-02-13 14:01:47 -0800183 def timestamp_head(self):
184 """
185 Return the timestamp of the head of queue or None if empty
186 """
Dan Talayco710438c2010-02-18 15:16:07 -0800187 rv = None
Dan Talaycoe226eb12010-02-18 23:06:30 -0800188 try:
Dan Talayco710438c2010-02-18 15:16:07 -0800189 rv = self.packets[0][1]
Dan Talaycoe226eb12010-02-18 23:06:30 -0800190 except:
191 rv = None
Dan Talayco710438c2010-02-18 15:16:07 -0800192 return rv
Dan Talayco3087a462010-02-13 14:01:47 -0800193
194 def flush(self):
195 """
196 Clear the packet queue
197 """
Rich Lanedb9d8662012-07-26 18:04:24 -0700198 with self.parent.pkt_sync:
199 self.packets_discarded += len(self.packets)
200 self.packets = []
Dan Talayco3087a462010-02-13 14:01:47 -0800201
202 def send(self, packet):
203 """
204 Send a packet to the dataplane port
205 @param packet The packet data to send to the port
206 @retval The number of bytes sent
207 """
208 return self.socket.send(packet)
209
Dan Talayco3087a462010-02-13 14:01:47 -0800210 def register(self, handler):
211 """
212 Register a callback function to receive packets from this
Dan Talaycoe226eb12010-02-18 23:06:30 -0800213 port. The callback will be passed the packet, the
214 interface name and the port number (if set) on which the
Dan Talayco3087a462010-02-13 14:01:47 -0800215 packet was received.
216
217 To be implemented
218 """
219 pass
220
Dan Talayco1b3f6902010-02-15 14:14:19 -0800221 def show(self, prefix=''):
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500222
Dan Talayco1b3f6902010-02-15 14:14:19 -0800223 print prefix + "Name: " + self.interface_name
Dan Talayco710438c2010-02-18 15:16:07 -0800224 print prefix + "Pkts pending: " + str(len(self.packets))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800225 print prefix + "Pkts total: " + str(self.packets_total)
226 print prefix + "socket: " + str(self.socket)
Dan Talaycoe226eb12010-02-18 23:06:30 -0800227
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500228
229 def port_down(self,port_number,config):
230
231 """
232 Grabs a port from the dataplane ports and brings it down by
233 shutting the corresponding interface
234 @port_number The port number which has brought to be down
235 @interface_name The interface corresponding to the port that needs to
236 be brought down
237
238 """
239 interface_name = config["port_map"].get(port_number)
240 cmd = 'ifdown '+ interface_name
241 os.system(cmd)
242
243 def port_up(self,port_number,config):
244
245 """
246 Grabs a port from the dataplane ports and brings it up by
247 starting up the corresponding interface
248 @port_number The port number which has to brought up
249 @interface_name The interface corresponding to the port that has to
250 be brought up
251
252 """
253 interface_name = config["port_map"].get(port_number)
254 cmd = 'ifup '+ interface_name
255 os.system(cmd)
256
257
Rich Laneb42a31c2012-10-05 17:54:17 -0700258class DataPlanePortPcap(DataPlanePort):
259 """
260 Alternate port implementation using libpcap. This is required for recent
261 versions of Linux (such as Linux 3.2 included in Ubuntu 12.04) which
262 offload the VLAN tag, so it isn't in the data returned from a read on a raw
263 socket. libpcap understands how to read the VLAN tag from the kernel.
264 """
265
266 def __init__(self, interface_name, port_number, parent, max_pkts=1024):
267 DataPlanePort.__init__(self, interface_name, port_number, parent, max_pkts)
268
269 def interface_open(self, interface_name):
270 """
271 Open a PCAP interface.
272 """
273 self.pcap = pcap.pcap(interface_name)
274 self.pcap.setnonblock()
275 return self.pcap.fileno()
276
277 def run(self):
278 """
279 Activity function for class
280 """
281 self.running = True
282 while self.running:
283 try:
Rich Lane5b5da2d2012-12-22 19:56:32 -0800284 sel_in, sel_out, sel_err = select.select([self.socket, self.waker], [], [], 1)
Rich Laneb42a31c2012-10-05 17:54:17 -0700285 except:
286 print sys.exc_info()
287 self.logger.error("Select error, exiting")
288 break
289
290 if not self.running:
291 break
292
293 if (sel_in is None) or (len(sel_in) == 0):
294 continue
295
Rich Lane5b5da2d2012-12-22 19:56:32 -0800296 if self.waker in sel_in:
297 self.waker.wait()
298 continue
299
Rich Laneb42a31c2012-10-05 17:54:17 -0700300 # Enqueue packet
301 with self.parent.pkt_sync:
302 for (timestamp, rcvmsg) in self.pcap.readpkts():
Rich Laneb42a31c2012-10-05 17:54:17 -0700303 self.logger.debug("Pkt len " + str(len(rcvmsg)) +
Rich Laned2e93aa2012-12-05 17:55:46 -0800304 " in at " + str(timestamp) + " on port " +
Rich Laneb42a31c2012-10-05 17:54:17 -0700305 str(self.port_number))
306
307 if len(self.packets) >= self.max_pkts:
308 # Queue full, throw away oldest
309 self.packets.pop(0)
310 self.packets_discarded += 1
311 self.logger.debug("Discarding oldest packet to make room")
Rich Laned2e93aa2012-12-05 17:55:46 -0800312 self.packets.append((rcvmsg, timestamp))
Rich Laneb42a31c2012-10-05 17:54:17 -0700313 self.packets_total += 1
314 self.parent.pkt_sync.notify_all()
315
316 self.logger.info("Thread exit")
317
318 def kill(self):
319 """
320 Terminate the running thread
321 """
322 self.logger.debug("Port monitor kill")
323 self.running = False
Rich Lane5b5da2d2012-12-22 19:56:32 -0800324 self.waker.notify()
Rich Laneb42a31c2012-10-05 17:54:17 -0700325 # pcap object is closed on GC.
326
327 def send(self, packet):
328 """
329 Send a packet to the dataplane port
330 @param packet The packet data to send to the port
331 @retval The number of bytes sent
332 """
333 return self.pcap.inject(packet, len(packet))
Dan Talayco34089522010-02-07 23:07:41 -0800334
335class DataPlane:
336 """
337 Class defining access primitives to the data plane
338 Controls a list of DataPlanePort objects
339 """
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700340 def __init__(self, config=None):
Dan Talayco34089522010-02-07 23:07:41 -0800341 self.port_list = {}
Dan Talaycoe226eb12010-02-18 23:06:30 -0800342 # pkt_sync serves double duty as a regular top level lock and
343 # as a condition variable
344 self.pkt_sync = Condition()
345
346 # These are used to signal async pkt arrival for polling
347 self.want_pkt = False
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700348 self.exp_pkt = None
Dan Talaycoe226eb12010-02-18 23:06:30 -0800349 self.want_pkt_port = None # What port required (or None)
350 self.got_pkt_port = None # On what port received?
351 self.packets_pending = 0 # Total pkts in all port queues
Dan Talayco48370102010-03-03 15:17:33 -0800352 self.logger = logging.getLogger("dataplane")
Dan Talayco34089522010-02-07 23:07:41 -0800353
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700354 if config is None:
355 self.config = {}
356 else:
357 self.config = config;
358
359 ############################################################
360 #
361 # We use the DataPlanePort class defined here by
362 # default for all port traffic:
363 #
Rich Laneb42a31c2012-10-05 17:54:17 -0700364 if have_pypcap:
365 self.dppclass = DataPlanePortPcap
366 else:
367 self.logger.warning("Missing pypcap, VLAN tests may fail. See README for installation instructions.")
368 self.dppclass = DataPlanePort
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700369
370 ############################################################
371 #
372 # The platform/config can provide a custom DataPlanePort class
373 # here if you have a custom implementation with different
374 # behavior.
375 #
376 # Set config.dataplane.portclass = MyDataPlanePortClass
377 # where MyDataPlanePortClass has the same interface as the class
378 # DataPlanePort defined here.
379 #
380 if "dataplane" in self.config:
381 if "portclass" in self.config["dataplane"]:
382 self.dppclass = self.config["dataplane"]["portclass"]
383
384 if self.dppclass == None:
385 raise Exception("Problem determining DataPlanePort class.")
386
387
Dan Talayco34089522010-02-07 23:07:41 -0800388 def port_add(self, interface_name, port_number):
389 """
390 Add a port to the dataplane
391 TBD: Max packets for queue?
392 @param interface_name The name of the physical interface like eth1
393 @param port_number The port number used to refer to the port
394 """
Dan Talaycoe226eb12010-02-18 23:06:30 -0800395
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700396 self.port_list[port_number] = self.dppclass(interface_name,
397 port_number, self);
398
Dan Talayco34089522010-02-07 23:07:41 -0800399 self.port_list[port_number].start()
400
Jeffrey Townsend0e8b0922012-07-11 11:37:46 -0700401
402
Dan Talayco34089522010-02-07 23:07:41 -0800403 def send(self, port_number, packet):
404 """
405 Send a packet to the given port
406 @param port_number The port to send the data to
407 @param packet Raw packet data to send to port
408 """
Dan Talayco11c26e72010-03-07 22:03:57 -0800409 self.logger.debug("Sending %d bytes to port %d" %
410 (len(packet), port_number))
Dan Talayco34089522010-02-07 23:07:41 -0800411 bytes = self.port_list[port_number].send(packet)
412 if bytes != len(packet):
Dan Talayco48370102010-03-03 15:17:33 -0800413 self.logger.error("Unhandled send error, length mismatch %d != %d" %
Dan Talayco1b3f6902010-02-15 14:14:19 -0800414 (bytes, len(packet)))
Dan Talayco34089522010-02-07 23:07:41 -0800415 return bytes
416
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500417
418
419
Dan Talayco34089522010-02-07 23:07:41 -0800420 def flood(self, packet):
421 """
422 Send a packet to all ports
423 @param packet Raw packet data to send to port
424 """
425 for port_number in self.port_list.keys():
426 bytes = self.port_list[port_number].send(packet)
427 if bytes != len(packet):
Dan Talayco48370102010-03-03 15:17:33 -0800428 self.logger.error("Unhandled send error" +
Dan Talayco1b3f6902010-02-15 14:14:19 -0800429 ", port %d, length mismatch %d != %d" %
430 (port_number, bytes, len(packet)))
Dan Talayco34089522010-02-07 23:07:41 -0800431
Rich Lanedb9d8662012-07-26 18:04:24 -0700432 # Returns the port with the oldest packet, or None if no packets are queued.
433 def oldest_port(self):
434 min_port = None
435 min_time = float('inf')
436 for port in self.port_list.values():
437 ptime = port.timestamp_head()
438 if ptime and ptime < min_time:
439 min_time = ptime
440 min_port = port
441 return min_port
442
443 # Dequeues and yields packets in the order they were received.
444 # Yields (port, packet, received time).
445 # If port_number is not specified yields packets from all ports.
446 def packets(self, port_number=None):
447 while True:
448 if port_number == None:
449 port = self.oldest_port()
450 else:
451 port = self.port_list[port_number]
452
453 if port == None or len(port.packets) == 0:
454 self.logger.debug("Out of packets for port %s" % str(port_number))
455 # Out of packets
456 break
457
458 pkt, time = port.packets.pop(0)
459 yield (port, pkt, time)
460
Rich Lane8806bc42012-07-26 19:18:37 -0700461 def poll(self, port_number=None, timeout=-1, exp_pkt=None):
Dan Talaycoe226eb12010-02-18 23:06:30 -0800462 """
463 Poll one or all dataplane ports for a packet
464
465 If port_number is given, get the oldest packet from that port.
466 Otherwise, find the port with the oldest packet and return
467 that packet.
Dan Talayco1729fdb2012-05-03 09:35:56 -0700468
469 If exp_pkt is true, discard all packets until that one is found
470
Dan Talaycoe226eb12010-02-18 23:06:30 -0800471 @param port_number If set, get packet from this port
Dan Talayco11c26e72010-03-07 22:03:57 -0800472 @param timeout If positive and no packet is available, block
Dan Talaycoe226eb12010-02-18 23:06:30 -0800473 until a packet is received or for this many seconds
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700474 @param exp_pkt If not None, look for this packet and ignore any
Dan Talayco1729fdb2012-05-03 09:35:56 -0700475 others received. Note that if port_number is None, all packets
476 from all ports will be discarded until the exp_pkt is found
Dan Talaycoe226eb12010-02-18 23:06:30 -0800477 @return The triple port_number, packet, pkt_time where packet
478 is received from port_number at time pkt_time. If a timeout
479 occurs, return None, None, None
480 """
481
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700482 if exp_pkt and not port_number:
Dan Talayco1729fdb2012-05-03 09:35:56 -0700483 self.logger.warn("Dataplane poll with exp_pkt but no port number")
484
Rich Lanedb9d8662012-07-26 18:04:24 -0700485 # Retrieve the packet. Returns (port number, packet, time).
486 def grab():
487 self.logger.debug("Grabbing packet")
488 for (port, pkt, time) in self.packets(port_number):
489 self.logger.debug("Checking packet from port %d" % port.port_number)
Dan Talayco1729fdb2012-05-03 09:35:56 -0700490 if not exp_pkt or match_exp_pkt(exp_pkt, pkt):
Rich Lanedb9d8662012-07-26 18:04:24 -0700491 return (port, pkt, time)
492 self.logger.debug("Did not find packet")
493 return None
Dan Talaycoe226eb12010-02-18 23:06:30 -0800494
Rich Lanedb9d8662012-07-26 18:04:24 -0700495 with self.pkt_sync:
496 ret = timed_wait(self.pkt_sync, grab, timeout=timeout)
Dan Talayco34089522010-02-07 23:07:41 -0800497
Rich Lanedb9d8662012-07-26 18:04:24 -0700498 if ret != None:
499 (port, pkt, time) = ret
500 return (port.port_number, pkt, time)
501 else:
502 self.logger.debug("Poll time out, no packet from " + str(port_number))
503 return (None, None, None)
Dan Talayco34089522010-02-07 23:07:41 -0800504
Dan Talayco48370102010-03-03 15:17:33 -0800505 def kill(self, join_threads=True):
Dan Talayco1b3f6902010-02-15 14:14:19 -0800506 """
507 Close all sockets for dataplane
Dan Talayco710438c2010-02-18 15:16:07 -0800508 @param join_threads If True call join on each thread
Dan Talayco1b3f6902010-02-15 14:14:19 -0800509 """
Dan Talayco34089522010-02-07 23:07:41 -0800510 for port_number in self.port_list.keys():
511 self.port_list[port_number].kill()
Rich Lane4d46dbd2012-12-22 19:26:19 -0800512
513 if join_threads:
514 for port_number in self.port_list.keys():
Dan Talayco48370102010-03-03 15:17:33 -0800515 self.logger.debug("Joining " + str(port_number))
Dan Talayco1b3f6902010-02-15 14:14:19 -0800516 self.port_list[port_number].join()
Dan Talayco34089522010-02-07 23:07:41 -0800517
Dan Talayco48370102010-03-03 15:17:33 -0800518 self.logger.info("DataPlane shutdown")
Dan Talayco1b3f6902010-02-15 14:14:19 -0800519
520 def show(self, prefix=''):
521 print prefix + "Dataplane Controller"
Dan Talaycoe226eb12010-02-18 23:06:30 -0800522 print prefix + "Packets pending" + str(self.packets_pending)
Dan Talayco1b3f6902010-02-15 14:14:19 -0800523 for pnum, port in self.port_list.items():
524 print prefix + "OpenFlow Port Number " + str(pnum)
525 port.show(prefix + ' ')
526
ShreyaPanditacd8e1cf2012-11-28 11:44:42 -0500527
528 def port_down(self,port_number):
529 """Brings the specified port down"""
530 self.port_list[port_number].port_down(port_number,self.config)
531
532
533 def port_up(self,port_number):
534 """Brings the specified port up"""
535 self.port_list[port_number].port_up(port_number,self.config)