Dan Talayco | 3408952 | 2010-02-07 23:07:41 -0800 | [diff] [blame] | 1 | """ |
| 2 | OpenFlow Test Framework |
| 3 | |
| 4 | Dataplane class |
| 5 | |
| 6 | Provide the interface to the control the set of ports being used |
| 7 | to stimulate the switch under test. |
| 8 | |
| 9 | See the class dataplaneport for more details. This class wraps |
| 10 | a set of those objects allowing general calls and parsing |
| 11 | configuration. |
| 12 | |
| 13 | """ |
| 14 | |
| 15 | from dataplaneport import * |
| 16 | |
| 17 | class DataPlane: |
| 18 | """ |
| 19 | Class defining access primitives to the data plane |
| 20 | Controls a list of DataPlanePort objects |
| 21 | """ |
| 22 | def __init__(self): |
| 23 | self.port_list = {} |
| 24 | |
| 25 | def port_add(self, interface_name, port_number): |
| 26 | """ |
| 27 | Add a port to the dataplane |
| 28 | TBD: Max packets for queue? |
| 29 | @param interface_name The name of the physical interface like eth1 |
| 30 | @param port_number The port number used to refer to the port |
| 31 | """ |
| 32 | |
| 33 | self.port_list[port_number] = DataPlanePort(interface_name) |
| 34 | self.port_list[port_number].start() |
| 35 | |
| 36 | def send(self, port_number, packet): |
| 37 | """ |
| 38 | Send a packet to the given port |
| 39 | @param port_number The port to send the data to |
| 40 | @param packet Raw packet data to send to port |
| 41 | """ |
| 42 | bytes = self.port_list[port_number].send(packet) |
| 43 | if bytes != len(packet): |
| 44 | print "Unhandled send error, length mismatch %d != %d" % \ |
| 45 | (bytes, len(packet)) |
| 46 | return bytes |
| 47 | |
| 48 | def flood(self, packet): |
| 49 | """ |
| 50 | Send a packet to all ports |
| 51 | @param packet Raw packet data to send to port |
| 52 | """ |
| 53 | for port_number in self.port_list.keys(): |
| 54 | bytes = self.port_list[port_number].send(packet) |
| 55 | if bytes != len(packet): |
| 56 | print "Unhandled send error" + \ |
| 57 | ", port %d, length mismatch %d != %d" % \ |
| 58 | (port_number, bytes, len(packet)) |
| 59 | |
| 60 | def packet_get(self, port_number=None): |
| 61 | """ |
| 62 | Get a packet from the data plane |
| 63 | If port_number is given, get the packet from that port. |
| 64 | Otherwise, find the port with the oldest packet and return |
| 65 | that packet. |
| 66 | @param port_number If set, get packet from this port |
| 67 | @retval The triple port_number, packet, pkt_time where packet |
| 68 | is received from port_number at time pkt_time. |
| 69 | """ |
| 70 | |
| 71 | if port_number: |
| 72 | if self.port_list[port_number].packets_pending != 0: |
| 73 | pkt, time = self.port_list[port_number].dequeue() |
| 74 | return port_number, pkt, time |
| 75 | else: |
| 76 | return None, None, None |
| 77 | |
| 78 | # Find port with oldest packet |
| 79 | min_time = 0 |
| 80 | min_port = -1 |
| 81 | for port_number in self.port_list.keys(): |
| 82 | ptime = self.port_list[port_number].timestamp_head() |
| 83 | if ptime: |
| 84 | if (min_port == -1) or (ptime < min_time): |
| 85 | min_time = ptime |
| 86 | min_port = port_number |
| 87 | |
| 88 | if min_port == -1: |
| 89 | return None, None, None |
| 90 | |
| 91 | pkt, time = self.port_list[min_port].dequeue() |
| 92 | return min_port, pkt, time |
| 93 | |
| 94 | def kill(self): |
| 95 | for port_number in self.port_list.keys(): |
| 96 | self.port_list[port_number].kill() |
| 97 | |
| 98 | print "DataPlane shutdown" |