Skip to content

Tutorial

In this tutorial we will walk through the ostinato example.py script that we used to verify the installation.

We start with importing the required modules and classes -

import os
import time

from ostinato.core import ost_pb, DroneProxy
from ostinato.protocols.mac_pb2 import mac, Mac
from ostinato.protocols.ip4_pb2 import ip4, Ip4

Setup some variables and create a DroneProxy object that will act as a proxy to communicate with drone -

host_name = '127.0.0.1'
tx_port_number = 0
rx_port_number = 0
drone = DroneProxy(host_name)

Before we can instruct drone to do anything, we need to connect to drone. Once connected, we can invoke operations on drone. We query drone for the list of ports and then retrieve configuration for all the ports

    drone.connect()

    port_id_list = drone.getPortIdList()
    port_config_list = drone.getPortConfig(port_id_list)

    print('Port List')
    print('---------')
    for port in port_config_list.port:
        print('%d.%s (%s)' % (port.port_id.id, port.name, port.description))

Several of the DroneProxy's methods, including the ones for transmit and capture, take a list of ports to operate on, so we set these up next.

    tx_port = ost_pb.PortIdList()
    tx_port.port_id.add().id = tx_port_number;

    rx_port = ost_pb.PortIdList()
    rx_port.port_id.add().id = rx_port_number;

Configuring a stream on a port is a two-step process - add + configure.

First we assign a stream id and then add it -

    stream_id = ost_pb.StreamIdList()
    stream_id.port_id.CopyFrom(tx_port.port_id[0])
    stream_id.stream_id.add().id = 1
    drone.addStream(stream_id)

This just adds a 'default' stream. We then configure the stream using the same stream id as what we assigned earlier -

    stream_cfg = ost_pb.StreamConfigList()
    stream_cfg.port_id.CopyFrom(tx_port.port_id[0])
    s = stream_cfg.stream.add()
    s.stream_id.id = stream_id.stream_id[0].id
    s.core.is_enabled = True
    s.control.num_packets = 5

NOTE: By default when you add a stream, it is disabled. You need to set Stream.core.is_enabled to True to enable it.

After configuring basic stream parameters such as number of packets, we configure the protocols in the stream. Adding a protocol to a stream is a 3-step process.

  • First we add a protocol with protocol.add()
  • Then we specify the specific protocol to use by assigning protocol_id.id to one of the various ost_pb.Protocol.kXXXFieldNumber
  • Finally we configure that protocol's fields - the protocol's fields are accessed using the Protocol.Extensions[XXX] dictionary
  • If a protocol field is not set explicitly, a default value will be used in the generated packet

After setting up the stream parameters, we call modifyStream to configure the default stream installed by addStream() with the values given here -

    # setup stream protocols as mac:eth2:ip4:udp:payload
    p = s.protocol.add()
    p.protocol_id.id = ost_pb.Protocol.kMacFieldNumber
    p.Extensions[mac].dst_mac_mode = Mac.e_mm_fixed
    p.Extensions[mac].src_mac_mode = Mac.e_mm_fixed
    p.Extensions[mac].dst_mac = 0x001122334455 # 00:11:22:33:44:55
    p.Extensions[mac].src_mac = 0x00aabbccddee # 00:aa:bb:cc:dd:ee

    p = s.protocol.add()
    p.protocol_id.id = ost_pb.Protocol.kEth2FieldNumber

    p = s.protocol.add()
    p.protocol_id.id = ost_pb.Protocol.kIp4FieldNumber
    # reduce typing by creating a shorter reference to p.Extensions[ip4]
    ip = p.Extensions[ip4]
    ip.src_ip = 0x01020304 # 1.2.3.4
    ip.dst_ip = 0x05060708 # 5.6.7.8
    ip.dst_ip_mode = Ip4.e_im_inc_host

    s.protocol.add().protocol_id.id = ost_pb.Protocol.kUdpFieldNumber
    s.protocol.add().protocol_id.id = ost_pb.Protocol.kPayloadFieldNumber

    drone.modifyStream(stream_cfg)

Before we start transmitting the stream, we build the generated packets and clear the port statistics -

    build_cfg = ost_pb.BuildConfig()
    build_cfg.port_id.CopyFrom(tx_port.port_id[0])
    ack = drone.build(build_cfg)
    if (ack.status): # error?
        log.error('packets prebuild error: %s' % ack.notes)

    drone.clearStats(tx_port)
    drone.clearStats(rx_port)

Now we can start transmitting the stream that we configured. Since we want to capture the transmitted packets when they appear on the rx port we ensure that we start capture before we start transmit and do the reverse while stopping.

    drone.startCapture(rx_port)
    drone.startTransmit(tx_port)

    # wait for transmit to finish
    time.sleep(7)

    drone.stopTransmit(tx_port)
    drone.stopCapture(rx_port)

We verify the transmit and receive by retreiving statistics

    tx_stats = drone.getStats(tx_port)
    rx_stats = drone.getStats(rx_port)

We retrieve the captured packets, save it in a temporary pcap file and use tshark to dump them

    buff = drone.getCaptureBuffer(rx_port.port_id[0])
    drone.saveCaptureBuffer(buff, 'capture.pcap')
    os.system('tshark -r capture.pcap')
    os.remove('capture.pcap')

Finally, we cleanup by deleting the stream that we configured and disconnect from drone

    drone.deleteStream(stream_id)
    drone.disconnect()

Download/View the full example.py

Auto resolve Mac addresses

The above example uses a stream with fixed and known values of Mac addresses. You could instead configure to it to resolve (make sure you assign source IP correctly so that ARP resolution succeeds) -

    # setup stream protocols as mac:eth2:ip4:udp:payload
    p = s.protocol.add()
    p.protocol_id.id = ost_pb.Protocol.kMacFieldNumber
    p.Extensions[mac].dst_mac_mode = Mac.e_mm_resolve
    p.Extensions[mac].src_mac_mode = Mac.e_mm_resolve

    p = s.protocol.add()
    p.protocol_id.id = ost_pb.Protocol.kIp4FieldNumber
    # get a reference to the IP fields using p.Extensions[ip4]
    ip = p.Extensions[ip4]
    ip.src_ip = 0xc0a8010a # 192.168.1.10
    ip.dst_ip = 0xc0a80114 # 192.168.1.20

    s.protocol.add().protocol_id.id = ost_pb.Protocol.kUdpFieldNumber
    s.protocol.add().protocol_id.id = ost_pb.Protocol.kPayloadFieldNumber

    drone.modifyStream(stream_cfg)

To actually resolve the mac addresses, call resolveDeviceNeighbors() before build() -

    drone.resolveDeviceNeighbors(tx_port)

    build_cfg = ost_pb.BuildConfig()
    build_cfg.port_id.CopyFrom(tx_port.port_id[0])
    drone.build()
Back to top