blob: f461dfae40b0413fda5953e45c03de35a3fa5fab [file] [log] [blame]
Dan Talayco34089522010-02-07 23:07:41 -08001"""
2OpenFlow Test Framework
3
4Dataplane Port class
5
6Control a dataplane port connected to the switch under test.
7
8Class inherits from thread so as to run in background allowing
9asynchronous callbacks (if needed, not required). Also supports
10polling.
11
12The port object thread maintains a queue. Incoming packets that
13are not handled by a callback function are placed in this queue for
14poll calls.
15
16"""
17
18import sys
19sys.path.append("../packet") # Needed?
20import os
21import socket
22import time
23import promisc
24from threading import Thread
25from threading import Lock
26
27ETH_P_ALL = 0x03
28RCV_TIMEOUT = 10000
29RCV_SIZE = 4096
30
31class DataPlanePort(Thread):
32 """
33 Class defining a port monitoring object.
34 Creates a promiscuous socket on a physical interface
35 Queues the packets received on that interface with time stamps
36 Inherits from Thread class as meant to run in background
37 Use accessors to dequeue packets for proper synchronization
38 """
39
40 def __init__(self, interface_name, max_pkts=1024):
41 """
42 Set up a port monitor object
43 @param interface_name The name of the physical interface like eth1
44 @param max_pkts Maximum number of pkts to keep in queue
45 """
46 Thread.__init__(self)
47 self.interface_name = interface_name
48 self.max_pkts = max_pkts
49 self.packets_pending = 0
50 self.packets_total = 0
51 self.packets = []
52 self.packet_times = []
53 self.sync = Lock()
54 self.socket = self.interface_open(interface_name)
55 print "Openned port monitor socket " + interface_name
56
57 def interface_open(self, interface_name):
58 """
59 Open a socket in a promiscuous mode for a data connection.
60 @param interface_name port name as a string such as 'eth1'
61 @retval s socket
62 """
63 s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
64 socket.htons(ETH_P_ALL))
65 s.bind((interface_name, 0))
66 promisc.set_promisc(s, interface_name)
67 s.settimeout(RCV_TIMEOUT)
68 return s
69
70 def kill(self):
71 """
72 Terminate the running thread
73 """
74 self.running = False
75 self.socket.close()
76 print "Port monitor for " + self.interface_name + " exiting"
77
78 def run(self):
79 """
80 Activity function for class
81 """
82 self.running = True
83 while self.running:
84 try:
85 rcvmsg = self.socket.recv(RCV_SIZE)
86 rcvtime = time.clock()
87
88 self.sync.acquire()
89 self.packets.append(rcvmsg)
90 self.packet_times.append(rcvtime)
91 self.packets_pending += 1
92 self.packets_total += 1
93 self.sync.release()
94
95 except socket.timeout:
96 print "Socket timeout for " + self.interface_name
97 except socket.error:
98 print "Socket closed for " + self.interface_name
99 if self.running:
100 self.kill()
101 break
102
103 def dequeue(self):
104 """
105 Get the oldest packet in the queue
106 """
107 self.sync.acquire()
108 pkt = self.packets.pop(0)
109 pkt_time = self.packet_times.pop(0)
110 self.packets_pending -= 1
111 self.sync.release()
112 return pkt, pkt_time
113
114 def timestamp_head(self):
115 """
116 Return the timestamp of the head of queue or None if empty
117 """
118 if self.packets_pending:
119 return self.packet_times[0]
120 return None
121
122 def flush(self):
123 """
124 Clear the packet queue
125 """
126 self.sync.acquire()
127 self.packets = []
128 self.packet_times = []
129 self.packets_pending = 0
130 self.sync.release()
131
132
133 def send(self, packet):
134 """
135 Send a packet to the dataplane port
136 @param packet The packet data to send to the port
137 @retval The number of bytes sent
138 """
139 return self.socket.send(packet)
140
141
142 def register(self, handler):
143 """
144 Register a callback function to receive packets from this
145 port. The callback will be passed the packet, the
146 interface name and the port number (if set) on which the
147 packet was received.
148
149 To be implemented
150 """
151 pass
152