class Drone(): def __init__(self, host_name='127.0.0.1', port_number=7878, tx_port_list=None, rx_port_list=None): self.__drone = DroneProxy(host_name, port_number) if tx_port_list: self.__tx_port_list = tx_port_list.all_ports else: self.__tx_port_list = None if rx_port_list: self.__rx_port_list = rx_port_list.all_ports else: self.__rx_port_list = None def connect(self): self.__drone.connect() self.tx_port_clear_stats() self.rx_port_clear_stats() return self def disconnect(self): self.__drone.disconnect() return self def add_stream_list(self, stream_list): self.current_stream_list = stream_list self.__drone.addStream(stream_list.all_streams) self.__drone.modifyStream(stream_list.all_streams_configurations) return self def remove_stream_list(self, stream_id_list): self.__drone.deleteStream(stream_id_list) return self def remove_current_stream_list(self): assert(self.current_stream_list) self.__drone.deleteStream(self.current_stream_list.all_streams) return self def fetch_stream_id_list(self): assert(self.__tx_port_list) stream_id_list = self.__drone.getStreamIdList(self.__tx_port_list.port_id[0]) return stream_id_list def fetch_port_id_list(self): port_id_list = self.__drone.getPortIdList() return port_id_list def get_port_config_list(self): port_config_list = self.__drone.getPortConfig(self.fetch_port_id_list()) return port_config_list def start_transmit(self): assert(self.__tx_port_list) self.tx_port_clear_stats() self.__drone.startTransmit(self.__tx_port_list) return self def wait_for_transmission_complete(self, time_out=None): time_start = time.time() while True: time.sleep(1) tx_stats = self.fetch_stats_tx_port() print('transmit rate %s bps' % (tx_stats.tx_bps * 8)) if (not tx_stats.state.is_transmit_on)\ or (time_out and (time.time() - time_start > time_out)): break else: print('waiting for transmit to finish ,elapsed time %s seconds' % (time.time() - time_start)) print('transmit total time %s seconds' % (time.time() - time_start)) return self def stop_transmit(self): assert(self.__tx_port_list) self.__drone.stopTransmit(self.__tx_port_list) return self def __start_capture(self, port_list): assert(port_list) self.__drone.startCapture(port_list) def __stop_capture(self, port_list): assert(port_list) self.__drone.stopCapture(port_list) def __clear_stats(self, port_list): # assert(port) if port_list: self.__drone.clearStats(port_list) def __fetch_stats_port(self, port_list): assert(port_list) stats = self.__drone.getStats(port_list) return stats.port_stats[0] def __fetch_capture_buffer(self, port_list, buffer_file_name='capture.pcap'): assert(port_list) buffer = self.__drone.getCaptureBuffer(port_list.port_id[0]) self.__drone.saveCaptureBuffer(buffer, buffer_file_name) # os.system('tshark -r ' + buffer_file_name) # os.remove(buffer_file_name) def tx_port_start_capture(self): self.__start_capture(self.__tx_port_list) return self def tx_port_stop_capture(self): self.__stop_capture(self.__tx_port_list) return self def tx_port_clear_stats(self): self.__clear_stats(self.__tx_port_list) return self def rx_port_start_capture(self): self.__start_capture(self.__rx_port_list) return self def rx_port_stop_capture(self): self.__stop_capture(self.__rx_port_list) return self def rx_port_clear_stats(self): self.__clear_stats(self.__rx_port_list) return self def fetch_stats_tx_port(self): return self.__fetch_stats_port(self.__tx_port_list) def fetch_capture_buffer_tx_port(self): self.__fetch_capture_buffer(self.__tx_port_list, buffer_file_name='tx_port_capture.pcap') def fetch_stats_rx_port(self): return self.__fetch_stats_port(self.__rx_port_list) def fetch_capture_buffer_rx_port(self): self.__fetch_capture_buffer(self.__rx_port_list, buffer_file_name='rx_port_capture.pcap')
class Traffic(object): """Class for traffic streams""" def __init__(self): self.drone = DroneProxy('127.0.0.1') self.drone.connect() self.port_id_list = self.drone.getPortIdList() self.port_config_list = self.drone.getPortConfig(self.port_id_list) self.tx_port = ost_pb.PortIdList() self.rx_port = ost_pb.PortIdList() self.interfaces = self._getInterfaces() self.addedInterfaces = [] self.tx_stats = None def __del__(self): """Cleanup the streams""" for interface in self.interfaces: self.drone.deleteStream(interface['stream_id_list']) self.drone.disconnect() def _getInterfaces(self): """Create a list of interface dicts which can be used for streams""" interfaces = [] for port in self.port_config_list.port: stream_id_list = ost_pb.StreamIdList() stream_id_list.stream_id.add().id = 1 stream_id_list.stream_id.add().id = 2 stream_id_list.stream_id.add().id = 3 stream_id_list.stream_id.add().id = 4 stream_id_list.stream_id.add().id = 5 stream_id_list.port_id.id = port.port_id.id self.drone.addStream(stream_id_list) stream_cfg = ost_pb.StreamConfigList() stream_cfg.port_id.id = port.port_id.id interface = { 'name': port.name, 'port_id': port.port_id, 'port_id_id': port.port_id.id, 'stream_id_list': stream_id_list, 'stream_cfg': stream_cfg, 'stream_id': 1, } interfaces.append(interface) return interfaces def _cleanupRun(self): """Delete all current streams, so that we can create new once for the next run""" for interface in self.interfaces: stream_id_list = interface['stream_id_list'] port_id = interface['port_id_id'] self.drone.deleteStream(stream_id_list) self.drone.addStream(stream_id_list) stream_cfg = ost_pb.StreamConfigList() stream_cfg.port_id.id = port_id interface['stream_cfg'] = stream_cfg interface['stream_id'] = 1 def _getInterfaceByName(self, interface_name): """Return the interface dict for a given interface name""" for interface in self.interfaces: if interface['name'] == interface_name: return interface raise NameError('getInterface called for unknown interface name') def _getInterfaceByPortId(self, port_id): """Return the interface dict for a given interface name""" for interface in self.interfaces: if interface['port_id_id'] == port_id: return interface raise NameError('getInterface called for unknown interface name') def _getInterfaceId(self, interface_name): """Return the Ostinato ID for an interface name""" for interface in self.interfaces: if interface['name'] == interface_name: return interface['port_id_id'] raise NameError('getInterfaceId called for unknown interface {0}'. format(interface_name)) def getInterfaceNames(self): """Return a list of interface names which can be used for streams""" return [interface['name'] for interface in self.interfaces] def addInterface(self, interface_name): """Add an interface to the configuration. It will then be used for transmit and receive""" dbg_print('addInterface({0})'.format(interface_name)) self.addedInterfaces.append(interface_name) port_id = self._getInterfaceId(interface_name) self.rx_port.port_id.add().id = port_id self.tx_port.port_id.add().id = port_id def _getInterfaceMacAddress(self, interface): """Return the MAC address of an interface""" return 0x001020304000 + interface['port_id_id'] def _getInterfaceIPAddress(self, interface): """Return the IP address of an interface""" return 0xc0a83a0a + interface['port_id_id'] def _addEthernetHeader(self, stream, src_mac, dst_mac): """Add an Ethernet header to a stream""" proto = stream.protocol.add() proto.protocol_id.id = ost_pb.Protocol.kMacFieldNumber proto.Extensions[mac].src_mac = src_mac proto.Extensions[mac].dst_mac = dst_mac def _addEthertypeIP(self, stream): """Add an Ethernet Type header for IP to a stream""" proto = stream.protocol.add() proto.protocol_id.id = ost_pb.Protocol.kEth2FieldNumber proto.Extensions[eth2].type = 0x0800 proto.Extensions[eth2].is_override_type = True def _addIPHeader(self, stream, src_ip, dst_ip): """Add an IP header to a stream""" proto = stream.protocol.add() proto.protocol_id.id = ost_pb.Protocol.kIp4FieldNumber proto.Extensions[ip4].src_ip = src_ip proto.Extensions[ip4].dst_ip = dst_ip def _addUdpHeader(self, stream, src_port, dst_port): """Add a UDP header to a stream""" proto = stream.protocol.add() proto.protocol_id.id = ost_pb.Protocol.kUdpFieldNumber proto.Extensions[udp].is_override_src_port = True proto.Extensions[udp].is_override_dst_port = True proto.Extensions[udp].src_port = src_port proto.Extensions[udp].dst_port = dst_port def _addIGMPHeader(self, stream, igmp_type, group): """Add an IGMP header to a stream""" proto = stream.protocol.add() proto.protocol_id.id = ost_pb.Protocol.kIgmpFieldNumber proto.Extensions[igmp].type = igmp_type proto.Extensions[igmp].group_address.v4 = group def _addIGMPRequestHeader(self, stream, group): """Add an IGMP Request header to a stream""" self._addIGMPHeader(stream, IGMPv2_REQUEST, group) def _addStream(self, stream_cfg, interface, num_packets, packets_per_sec): """Add a stream to an interface, and return it""" stream = stream_cfg.stream.add() stream.stream_id.id = interface['stream_id'] interface['stream_id'] = interface['stream_id'] + 1 stream.core.is_enabled = True stream.core.frame_len = 128 stream.control.num_packets = num_packets stream.control.packets_per_sec = packets_per_sec return stream def _addUDPPacketStream(self, stream, src_mac, dst_mac, src_ip, dst_ip): """Add a UDP packets to a stream""" self._addEthernetHeader(stream, src_mac=src_mac, dst_mac=dst_mac) self._addEthertypeIP(stream) self._addIPHeader(stream, src_ip=src_ip, dst_ip=dst_ip) self._addUdpHeader(stream, 0x1234, 0x4321) proto = stream.protocol.add() proto.protocol_id.id = ost_pb.Protocol.kPayloadFieldNumber def addUDPStream(self, src_interface_name, dst_interface_name, num_packets, packets_per_sec): """Add a UDP stream from the source interface to the destination interface""" dbg_print('addUDPStream({0} {1} {2} {3})'.format(src_interface_name, dst_interface_name, num_packets, packets_per_sec)) src_interface = self._getInterfaceByName(src_interface_name) dst_interface = self._getInterfaceByName(dst_interface_name) stream_cfg = src_interface['stream_cfg'] stream = self._addStream(stream_cfg, src_interface, num_packets, packets_per_sec) src_mac = self._getInterfaceMacAddress(src_interface) dst_mac = self._getInterfaceMacAddress(dst_interface) src_ip = self._getInterfaceIPAddress(src_interface) dst_ip = self._getInterfaceIPAddress(dst_interface) self._addUDPPacketStream(stream, src_mac, dst_mac, src_ip, dst_ip) self.drone.modifyStream(stream_cfg) def addUDPBroadcastStream(self, src_interface_name, num_packets, packets_per_sec): """Add a UDP broadcast stream from the source interface to the broadcast address""" dbg_print('addUDPBroadcastStream({0} {1} {2})'. format(src_interface_name, num_packets, packets_per_sec)) src_interface = self._getInterfaceByName(src_interface_name) stream_cfg = src_interface['stream_cfg'] stream = self._addStream(stream_cfg, src_interface, num_packets, packets_per_sec) src_mac = self._getInterfaceMacAddress(src_interface) dst_mac = 0xffffffffffff src_ip = self._getInterfaceIPAddress(src_interface) dst_ip = 0xc0a82aff self._addUDPPacketStream(stream, src_mac, dst_mac, src_ip, dst_ip) self.drone.modifyStream(stream_cfg) def addUDPMulticastStream(self, src_interface_name, group_str, num_packets, packets_per_sec): """Add a UDP multicast stream from the source interface to the group address""" dbg_print('addUDPMulticastStream({0} {1} {2} {3})'. format(src_interface_name, group_str, num_packets, packets_per_sec)) src_interface = self._getInterfaceByName(src_interface_name) stream_cfg = src_interface['stream_cfg'] stream = self._addStream(stream_cfg, src_interface, num_packets, packets_per_sec) src_mac = self._getInterfaceMacAddress(src_interface) group = ipaddress.ip_address(group_str.decode()) dst_mac = 0x01005e000000 + (int(group) & 0x07fffff) src_ip = self._getInterfaceIPAddress(src_interface) dst_ip = int(group) self._addUDPPacketStream(stream, src_mac, dst_mac, src_ip, dst_ip) self.drone.modifyStream(stream_cfg) def addIGMPRequestStream(self, src_interface_name, group, num_packets, packets_per_sec): """Add a IGMP request stream from the source interface to the group address""" dbg_print('addIGMPStream({0} {1} {2})'. format(src_interface_name, group, num_packets)) src_interface = self._getInterfaceByName(src_interface_name) stream_cfg = src_interface['stream_cfg'] stream = self._addStream(stream_cfg, src_interface, num_packets, packets_per_sec) src_mac = self._getInterfaceMacAddress(src_interface) dst_mac = 0x01005e00001 src_ip = self._getInterfaceIPAddress(src_interface) dst_ip = group self._addEthernetHeader(stream, src_mac=src_mac, dst_mac=dst_mac) self._addEthertypeIP(stream) self._addIPHeader(stream, src_ip=src_ip, dst_ip=dst_ip) self._addIGMPRequestHeader(stream, group) self.drone.modifyStream(stream_cfg) def learningStream(self, interface_name): """Create a stream on the interface for bridge learning. Two broadcast packets will be sent, so allowing the switch to learn the source MAC address on the interface.""" dbg_print('learningStream({0})'.format(interface_name)) self.addUDPBroadcastStream(interface_name, 2, 1) def learning(self): """Perform learning on each port, by sending a couple of packet, so that the bridge learns the address on the interface""" dbg_print('learning') for interface_name in self.addedInterfaces: self.learningStream(interface_name) frame = inspect.stack()[1][0] method = inspect.stack()[1][3] test = get_class_from_frame(frame).__name__ self._run(test, method) def _saveCapture(self, testname, methodname, interface_name): """Save the capture file for one interface""" filename = "{0}-{1}-{2}.pcap".format(testname, methodname, interface_name) interface = self._getInterfaceByName(interface_name) buff = self.drone.getCaptureBuffer(interface['port_id']) self.drone.saveCaptureBuffer(buff, filename) def _saveCaptures(self, testname, methodname): """Save the capture files, using the test name as a prefix""" for interface_name in self.addedInterfaces: self._saveCapture(testname, methodname, interface_name) def _run(self, test, method): """Do the real work""" self.drone.clearStats(self.tx_port) self.drone.clearStats(self.rx_port) self.drone.startCapture(self.rx_port) self.drone.startTransmit(self.tx_port) done = False while not done: done = True tx_stats = self.drone.getStats(self.tx_port) for port_stats in tx_stats.port_stats: if port_stats.state.is_transmit_on: done = False time.sleep(1) self.drone.stopTransmit(self.tx_port) self.drone.stopCapture(self.rx_port) self.tx_stats = self.drone.getStats(self.tx_port) self._saveCaptures(test, method) self._cleanupRun() def run(self): """Run the streams""" dbg_print('run') frame = inspect.stack()[1][0] method = inspect.stack()[1][3] test = get_class_from_frame(frame).__name__ self._run(test, method) def getStats(self, interface_name): """Return the interface statistics""" dbg_print('getStats({0})'.format(interface_name)) port_id = self._getInterfaceId(interface_name) for port_stats in self.tx_stats.port_stats: if port_stats.port_id.id == port_id: stats = { 'rx_pkts': port_stats.rx_pkts, 'rx_pps': port_stats.rx_pps, 'rx_bps': port_stats.rx_bps, 'tx_pkts': port_stats.tx_pkts, 'tx_pps': port_stats.tx_pps, 'tx_bps': port_stats.tx_bps, 'rx_drops': port_stats.rx_drops, 'rx_errors': port_stats.rx_errors, 'rx_fifo_errors': port_stats.rx_fifo_errors, 'rx_frame_errors': port_stats.rx_frame_errors, } return stats
p = s.protocol.add() p.protocol_id.id = ost_pb.Protocol.kIp4FieldNumber ip = p.Extensions[ip4] ip.src_ip = int(ip_src, 16) ip.dst_ip = int(ip_dst, 16) p = s.protocol.add() p.protocol_id.id = ost_pb.Protocol.kUdpFieldNumber s.protocol.add().protocol_id.id = ost_pb.Protocol.kPayloadFieldNumber drone.modifyStream(stream_cfg) drone.clearStats(tx_port) drone.startTransmit(tx_port) # wait for transmit to finish try: time.sleep(1000) except KeyboardInterrupt: drone.stopTransmit(tx_port) drone.stopCapture(tx_port) stats = drone.getStats(tx_port) print(stats) drone.deleteStream(stream_id) drone.disconnect()
# start capture and transmit log.info('starting capture') drone.startCapture(rx_port) log.info('starting transmit') drone.startTransmit(tx_port) # wait for transmit to finish log.info('waiting for transmit to finish ...') time.sleep(7) # stop transmit and capture log.info('stopping transmit') drone.stopTransmit(tx_port) log.info('stopping capture') drone.stopCapture(rx_port) # get tx/rx stats log.info('retreiving stats') tx_stats = drone.getStats(tx_port) rx_stats = drone.getStats(rx_port) #log.info('--> (tx_stats)' + tx_stats.__str__()) #log.info('--> (rx_stats)' + rx_stats.__str__()) log.info('tx pkts = %d, rx pkts = %d' % (tx_stats.port_stats[0].tx_pkts, rx_stats.port_stats[0].rx_pkts)) # retrieve and dump received packets log.info('getting Rx capture buffer') buff = drone.getCaptureBuffer(rx_port.port_id[0]) drone.saveCaptureBuffer(buff, 'capture.pcap')