Generate HSR/PRP traffic using a custom protocol script

Ostinato Team bio photo By Ostinato Team

If you are using Ostinato on Linux, see “How to generate HSR/PRP traffic on Linux” - it is easier than using the custom protocol user-script described in this blog


In this post we will see how to generate the industrial-ethernet protocols HSR/PRP traffic using Ostinato custom protocol user-script.

The Ostinato custom protocol user-script is a powerful tool that allows you to generate traffic for any protocol - even if it is not supported by Ostinato natively.

All you need to do is write a few lines of Javascript code. We will show the code for HSR/PRP in this post that you can simply copy-paste into your Ostinato user-script.

HSR (High-availability Seamless Redundancy)

Let’s begin with the frame format for HSR.

HSR is added as a header to an Ethernet frame similar to VLAN tags.

+-----------------+---------+---------+-----+
| Ethernet Header | HSR Tag | Payload | FCS |
+-----------------+---------+---------+-----+

The HSR tag is 6 bytes long and contains the following fields.

+----------+-------------+------------+-----------------+
|  Path Id |  Frame Size | Seq Number | Payload EthType |
|  4 bits  |    12 bits  |   16 bits  |     16 bits     |
+----------+-------------+------------+-----------------+

First create a Ostinato stream with all the protocols that you need, except the HSR protocol.

e.g. Mac | Ethernet | IP | UDP | Pattern Payload

Then switch to the advanced mode of protocol selection and insert {Script} between the Ethernet and IP protocols.

Ostinato HSR stream protocols

For the user-script, copy the following code and paste it into the user-script field.

protocol.name = "HSR"

protocol.protocolFrameSize = function() { return 6; }

protocol.protocolFrameValue = function(index)
{
    var pathId = 0x1; // Change if required

    var frameSz = protocol.protocolFramePayloadSize(index)+6;
    var type = protocol.payloadProtocolId(Protocol.ProtocolIdEth);

    var pfv = new Array(6);

    pfv[0] = pathId << 4 | (frameSz & 0xF00) >> 8;
    pfv[1] = frameSz & 0xFF;

    // Seq # will be set/incremented by variable fields; set to zero here
    pfv[2] = 0;
    pfv[3] = 0;

    pfv[4] = (type >> 8) & 0xFF;
    pfv[5] = type & 0xFF;

    return pfv;
}

protocol.protocolId = function(type)
{
    if (type == Protocol.ProtocolIdEth)
        return 0x892f;
    return 0;
}

The code is pretty much self-explanatory. In case of any questions, please refer to the Ostinato custom protocols’ user-script documentation.

You can change the pathId value as required.

For incrementing the sequence number with every packet, we will use the Variable Fields feature as shown below.

  • Protocol: HSR
  • Field: Custom
  • Type: Counter16
  • Offset: 2
  • Mode: Increment

HSR Sequence Number Variable Field

Here’s a sample HSR stream that you can download and open in Ostinato.

PRP (Parallel Redundancy Protocol)

PRP is added as a trailer (RCT - Redundancy Control Trailer) instead of a header. Let’s look at the frame format first.

+-----------------+---------+---------+-----+
| Ethernet Header | Payload | PRP RCT | FCS |
+-----------------+---------+---------+-----+

The PRP RCT is 6 bytes long and contains similar fields as the HSR tag but in a different order.

+-------------+--------+------------+------------+
|  Seq Number | Lan Id | Frame Size | PRP Suffix |
|   16 bits   | 4 bits |   12 bits  |  16 bits   |
+-------------+--------+------------+------------+

The PRP suffix is a fixed value of 0x88fb.

To create a PRP packet, first create a Ostinato stream with all the protocols that you need, except the PRP protocol.

e.g. Mac | Ethernet | IP | UDP | Pattern Payload

Then switch to the advanced mode of protocol selection and insert {Script} at the very end - after the Pattern payload protocol (DATA).

Ostinato PRP stream protocols

For the user-script, copy the following code and paste it into the user-script field.

protocol.name = "PRP"

protocol.protocolFrameSize = function() { return 6; }

protocol.protocolFrameValue = function(index)
{
    var lan = 0xA;
    var frameSz = protocol.protocolFrameOffset(index)+4-12;

    var pfv = new Array(4);

    // Seq # will be set/incremented by variable fields; don't care here
    pfv[0] = 0;
    pfv[1] = 0;

    pfv[2] = lan << 4 | (frameSz & 0xF00) >> 8;
    pfv[3] = frameSz & 0xFF;

    pfv[4] = 0x88;
    pfv[5] = 0xfb;

    return pfv;
}

You can change the lan value as required.

For incrementing the sequence number with every packet, we will again use the Variable Fields feature as we did for HSR (but with a different offset value)

  • Protocol: PRP
  • Field: Custom
  • Type: Counter16
  • Offset: 0
  • Mode: Increment

PRP Sequence Number Variable Field

A few more PRP adjustments

In case of PRP, we need to adjust the IP/UDP length to ignore the PRP RCT.

A quick way to figure out the adjustments to make is to send the packets as it is, capture in Wireshark and note down the following values:

  • IP Total Length
  • UDP Length

Then overwrite the value of the above fields in Ostinato by subtracting 6 (PRP RCT length) from each of the values as shown in Wireshark.

PRP IP Length Overrides

PRP UDP Length Overrides

We also need to override the UDP checksum as shown above. Again send the packets after adjusting the IP/UDP lengths, capture in Wireshark and note down the value that Wireshark says is the expected checksum and use that to fill the UDP checksum field.

📌 Please note that if you change the Ostinato stream frame length, you will need to adjust the IP/UDP length and checksum overrides accordingly.

Here’s a sample PRP stream that you can download and open in Ostinato.