Commit b637fe3c authored by Andreas Schmidt's avatar Andreas Schmidt
Browse files

Hardware timestamping support.

parent a45e3753
Loading
Loading
Loading
Loading
Loading

README

deleted100644 → 0
+0 −14
Original line number Diff line number Diff line
# Predictable Reliable Realtime Transport

## Docker

sudo docker run --rm --name=prrt_recv --net=host prrt receiver 5000 127
sudo docker run --rm --name=prrt_send --net=host prrt sender 127.0.0.1 5000 127



bridge=docker network create --subnet="10.5.1.0/24" prrt | cut -c1-12
ovs-vsctl add-port of-switch br-$bridge

docker run --rm --name=prrt_recv --network="prrt" -v=/opt/prrt:/output --ip=10.5.1.52 --cap-add NET_ADMIN git.nt.uni-saarland.de:4567/larn/prrt:develop receiver 5000 127
docker run --rm --name=prrt_send --network="prrt" -v=/opt/prrt:/output --ip=10.5.1.51 --cap-add NET_ADMIN git.nt.uni-saarland.de:4567/larn/prrt:develop sender 10.50.1.52 5000 127 rate 1mbit

README.md

0 → 100644
+52 −0
Original line number Diff line number Diff line
# Predictably Reliable Real-Time (PRRT)

## Hardware Timestamping

* Hardware timestamping can be enabled per socket by calling `PrrtSocket_enable_hardware_timestamping()` and specifying the interface.
* Requirements are a kernel that supports physical timestamping. Instructions can be found

### Compiling a hardware tmestamping enabled kernel on Ubuntu

* A detailed tutorial on kernel compilation can be found [here](https://help.ubuntu.com/community/Kernel/Compile).
* Create and enter a new folder, e.g. in your home directory that will store the newly compiled kernel.
* Run the following commands to download all resources required:

```bash
sudo apt install libncurses5 libncurses5-dev

sudo apt build-dep linux-image-`uname -r`
apt source linux-image-`uname -r`

cd linux-$(uname -r | awk '{split($1,a, "-"); print a[1]}')
```

* Copy the current kernel configuration to the current folder:

```bash
cp -vi /boot/config-`uname -r` .config
```

* Edit the `.config` file and ensure the following line is present (and the option is set to `y`):

```bash
...
CONFIG_NETWORK_PHY_TIMESTAMPING=y
...
```

* Call `make deb-pkg` (ideally with `-j5` or some other number to speed up the compilation by using multiple cores).
* Install the `linux-headers-*.deb` and `linux-image-*.deb` package via `dpkg -i` (where * stands for the respective kernel version).
* Reboot the system.


## Docker

The following shows how to run the PRRT sender and receiver on a host with OpenvSwitch.

```bash
bridge=$(docker network create --subnet="10.5.1.0/24" prrt | cut -c1-12) 
ovs-vsctl add-port of-switch br-$bridge 
 
docker run --rm --name=prrt_recv --network="prrt" -v=/opt/prrt:/output --ip=10.5.1.52 --cap-add NET_ADMIN docker.nt.uni-saarland.de/larn/prrt:develop receiver 5000 127 
docker run --rm --name=prrt_send --network="prrt" -v=/opt/prrt:/output --ip=10.5.1.51 --cap-add NET_ADMIN docker.nt.uni-saarland.de/larn/prrt:develop sender 10.50.1.52 5000 127 rate 1mbit
```
 No newline at end of file
+0 −3
Original line number Diff line number Diff line
#include <sys/time.h>
#include <stddef.h>
#include <stdlib.h>
#include "../util/common.h"
#include "../util/dbg.h"
#include "clock.h"
#include "packet.h"

prrtTimestamp_t PrrtClock_get_current_time_us()
{
+1 −1
Original line number Diff line number Diff line
@@ -27,8 +27,8 @@ prrtTimestamp_t PrrtClock_get_prrt_time_us(PrrtClock *clock);

bool PrrtClock_update(PrrtClock *clock, prrtTimestamp_t referenceTime, prrtTimedelta_t rtt);


#define diff_abs_ts(timeA, timeB) (prrtTimeDifference_t) abs(((prrtTimeDifference_t) timeA) - ((prrtTimeDifference_t)timeB))

#define PrrtClock_TimespecToPrrtTimestamp(timespec) ((prrtTimestamp_t) (1000000 * timespec.tv_sec + timespec.tv_nsec / 1000))

#endif //PRRT_CLOCK_H
+40 −55
Original line number Diff line number Diff line
@@ -24,23 +24,19 @@ static void *decode_redundancy_header(void *dstBuffer, const void *srcBuffer);

static void *decode_feedback_header(void *dstBuffer, const void *srcBuffer);

prrtPacketType_t PrrtPacket_type(PrrtPacket *packet_ptr)
{
prrtPacketType_t PrrtPacket_type(PrrtPacket *packet_ptr) {
    return (prrtPacketType_t) ((packet_ptr->type_priority >> 4) & 0x0F);
}

uint8_t PrrtPacket_priority(PrrtPacket *packet_ptr)
{
uint8_t PrrtPacket_priority(PrrtPacket *packet_ptr) {
    return (uint8_t) (packet_ptr->type_priority & 0x0F);
}

prrtPacketLength_t PrrtPacket_size(PrrtPacket *packet_ptr)
{
prrtPacketLength_t PrrtPacket_size(PrrtPacket *packet_ptr) {
    return (prrtPacketLength_t) (packet_ptr->payloadLength + PRRT_PACKET_GENERAL_HEADER_SIZE);
}

int PrrtPacket_print(PrrtPacket *packet_ptr)
{
int PrrtPacket_print(PrrtPacket *packet_ptr) {
    printf(" 0                   1                   2                   3\n"
                   " 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n"
                   "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n");
@@ -109,8 +105,7 @@ int PrrtPacket_print(PrrtPacket *packet_ptr)
    return 0;
}

PrrtPacket *PrrtPacket_copy(PrrtPacket *original)
{
PrrtPacket *PrrtPacket_copy(PrrtPacket *original) {
    PrrtPacket *newPacket = calloc(1, sizeof(PrrtPacket));
    check_mem(newPacket);
    void *payload = calloc(1, original->payloadLength);
@@ -131,8 +126,8 @@ PrrtPacket *PrrtPacket_copy(PrrtPacket *original)
    return NULL;
}

static PrrtPacket *create_header(uint8_t priority, prrtSequenceNumber_t seqno, prrtPacketLength_t size, uint8_t type, uint8_t index)
{
static PrrtPacket *
create_header(uint8_t priority, prrtSequenceNumber_t seqno, prrtPacketLength_t size, uint8_t type, uint8_t index) {
    PrrtPacket *packet = calloc(1, sizeof(PrrtPacket));
    check_mem(packet);

@@ -149,8 +144,7 @@ static PrrtPacket *create_header(uint8_t priority, prrtSequenceNumber_t seqno, p
    return NULL;
}

bool PrrtPacket_encode(void *buf_ptr, uint16_t buf_size, PrrtPacket *packet_ptr)
{
bool PrrtPacket_encode(void *buf_ptr, uint16_t buf_size, PrrtPacket *packet_ptr) {
    void *payload = packet_ptr->payload;

    check(packet_ptr->payloadLength + PRRT_PACKET_GENERAL_HEADER_SIZE <= buf_size, "Buffer too small.");
@@ -176,8 +170,7 @@ bool PrrtPacket_encode(void *buf_ptr, uint16_t buf_size, PrrtPacket *packet_ptr)
    return false;
}

void *encode_redundancy_header(void *buf_ptr, const void *payload)
{
void *encode_redundancy_header(void *buf_ptr, const void *payload) {
    const PrrtPacketRedundancyPayload *redundancyPayload = payload;

    prrtSequenceNumber_t *baseSeqNo = (prrtSequenceNumber_t *) buf_ptr;
@@ -195,8 +188,7 @@ void *encode_redundancy_header(void *buf_ptr, const void *payload)
    return buf_ptr;
}

void *encode_feedback_header(void *buf_ptr, const void *payload)
{
void *encode_feedback_header(void *buf_ptr, const void *payload) {
    const PrrtPacketFeedbackPayload *feedbackPayload = payload;

    uint32_t *receiverAddress = (uint32_t *) buf_ptr;
@@ -243,8 +235,7 @@ void *encode_feedback_header(void *buf_ptr, const void *payload)
    return buf_ptr;
}

void *encode_data_header(void *buf_ptr, const void *payload)
{
void *encode_data_header(void *buf_ptr, const void *payload) {
    const PrrtPacketDataPayload *data_payload = payload;

    prrtPacketLength_t *packetLength = (prrtPacketLength_t *) buf_ptr;
@@ -273,8 +264,7 @@ void *encode_data_header(void *buf_ptr, const void *payload)
    return buf_ptr;
}

void *encode_general_header(void *buf_ptr, const PrrtPacket *packet)
{
void *encode_general_header(void *buf_ptr, const PrrtPacket *packet) {
    uint8_t *type_priority = (uint8_t *) buf_ptr;
    *type_priority = packet->type_priority;
    buf_ptr += sizeof(uint8_t);
@@ -290,8 +280,7 @@ void *encode_general_header(void *buf_ptr, const PrrtPacket *packet)
    return buf_ptr;
}

bool PrrtPacket_decode(void *srcBuffer, uint16_t srcBufferSize, PrrtPacket *targetPacket)
{
bool PrrtPacket_decode(void *srcBuffer, uint16_t srcBufferSize, PrrtPacket *targetPacket) {
    prrtPacketLength_t payload_len = (prrtPacketLength_t) (srcBufferSize - PRRT_PACKET_GENERAL_HEADER_SIZE);
    targetPacket->type_priority = *(uint8_t *) srcBuffer;
    srcBuffer += 1;
@@ -326,8 +315,7 @@ bool PrrtPacket_decode(void *srcBuffer, uint16_t srcBufferSize, PrrtPacket *targ
    return false;
}

void *decode_redundancy_header(void *dstBuffer, const void *srcBuffer)
{
void *decode_redundancy_header(void *dstBuffer, const void *srcBuffer) {
    PrrtPacketRedundancyPayload *redundancyPayload = (PrrtPacketRedundancyPayload *) srcBuffer;

    prrtSequenceNumber_t *baseSeqNo = (prrtSequenceNumber_t *) dstBuffer;
@@ -345,8 +333,7 @@ void *decode_redundancy_header(void *dstBuffer, const void *srcBuffer)
    return dstBuffer;
}

void *decode_feedback_header(void *dstBuffer, const void *srcBuffer)
{
void *decode_feedback_header(void *dstBuffer, const void *srcBuffer) {
    PrrtPacketFeedbackPayload *feedback_payload = (PrrtPacketFeedbackPayload *) srcBuffer;

    uint32_t *receiverAddr = (uint32_t *) dstBuffer;
@@ -393,8 +380,7 @@ void *decode_feedback_header(void *dstBuffer, const void *srcBuffer)
    return dstBuffer;
}

void *decode_data_header(void *dstBuffer, const void *srcBuffer)
{
void *decode_data_header(void *dstBuffer, const void *srcBuffer) {
    PrrtPacketDataPayload *data_payload = (PrrtPacketDataPayload *) srcBuffer;

    prrtPacketLength_t *dataLength = (prrtPacketLength_t *) dstBuffer;
@@ -424,8 +410,7 @@ void *decode_data_header(void *dstBuffer, const void *srcBuffer)
}


int PrrtPacket_destroy(PrrtPacket *packet)
{
int PrrtPacket_destroy(PrrtPacket *packet) {
    if (packet->payload != NULL) {
        free(packet->payload);
    }
@@ -435,10 +420,10 @@ int PrrtPacket_destroy(PrrtPacket *packet)

PrrtPacket *PrrtPacket_create_data_packet(uint8_t priority, const void *payloadPointer,
                                          prrtPacketLength_t dataLength, prrtSequenceNumber_t sequenceNumber,
                                          prrtTimedelta_t targetDelay)
{
                                          prrtTimedelta_t targetDelay) {
    PrrtPacket *packet = create_header(priority, sequenceNumber,
                                       (prrtPacketLength_t) (dataLength + PRRT_PACKET_DATA_HEADER_SIZE), PACKET_TYPE_DATA, 0);
                                       (prrtPacketLength_t) (dataLength + PRRT_PACKET_DATA_HEADER_SIZE),
                                       PACKET_TYPE_DATA, 0);

    PrrtPacketDataPayload *dataPayload = calloc(1, packet->payloadLength);
    check_mem(dataPayload);
@@ -447,7 +432,6 @@ PrrtPacket *PrrtPacket_create_data_packet(uint8_t priority, const void *payloadP
    dataPayload->dataLength = dataLength;
    dataPayload->timestamp = PrrtClock_get_current_time_us();
    dataPayload->packetTimeout_us = dataPayload->timestamp + targetDelay;
	debug(DEBUG_PACKET, "timeout = %lu + %lu", (unsigned long) dataPayload->timestamp, (unsigned long) targetDelay);
    dataPayload->groupRTT_us = 0;
    dataPayload->decodingTimeout_us = 150; // TODO: payload->decodingTimeout_us
    dataPayload->feedbackTimer_us = 170; // TODO: payload->feedback_timer
@@ -460,11 +444,13 @@ PrrtPacket *PrrtPacket_create_data_packet(uint8_t priority, const void *payloadP
    return NULL;
}

PrrtPacket *PrrtPacket_reconstruct_data_packet(PrrtPacketDataPayload *payload, prrtIndex_t index, prrtSequenceNumber_t sequenceNumber) {
PrrtPacket *PrrtPacket_reconstruct_data_packet(PrrtPacketDataPayload *payload, prrtIndex_t index,
                                               prrtSequenceNumber_t sequenceNumber) {
    prrtPacketLength_t dataLength = payload->dataLength;

    PrrtPacket *packet = create_header(0, sequenceNumber,
                                       (prrtPacketLength_t) (dataLength + PRRT_PACKET_DATA_HEADER_SIZE), PACKET_TYPE_DATA, index);
                                       (prrtPacketLength_t) (dataLength + PRRT_PACKET_DATA_HEADER_SIZE),
                                       PACKET_TYPE_DATA, index);

    PrrtPacketDataPayload *dataPayload = calloc(1, packet->payloadLength);
    check_mem(dataPayload);
@@ -482,8 +468,8 @@ PrrtPacket *PrrtPacket_reconstruct_data_packet(PrrtPacketDataPayload *payload, p
PrrtPacket *PrrtPacket_create_redundancy_packet(uint8_t priority, void *payloadPointer,
                                                prrtPacketLength_t payloadLength,
                                                prrtSequenceNumber_t sequenceNumber, uint8_t index,
                                                prrtSequenceNumber_t baseSequenceNumber, PrrtCodingParams* codingParams)
{
                                                prrtSequenceNumber_t baseSequenceNumber,
                                                PrrtCodingParams *codingParams) {
    PrrtPacket *packet = create_header(priority, sequenceNumber,
                                       (prrtPacketLength_t) (payloadLength + PRRT_PACKET_REDUNDANCY_HEADER_SIZE),
                                       PACKET_TYPE_REDUNDANCY, index);
@@ -508,8 +494,7 @@ PrrtPacket *PrrtPacket_create_feedback_packet(uint8_t priority, uint8_t index, p
                                              prrtTimedelta_t groupRTT, prrtSequenceNumber_t gapLength,
                                              prrtSequenceNumber_t gapCount, prrtSequenceNumber_t burstLength,
                                              prrtSequenceNumber_t burstCount, uint32_t bandwidth,
                                              uint32_t receiverAddr, prrtTimestamp_t forwardTripTime)
{
                                              uint32_t receiverAddr, prrtTimestamp_t forwardTripTime) {
    PrrtPacket *packet = create_header(priority, sequenceNumber, PRRT_PACKET_FEEDBACK_HEADER_SIZE, PACKET_TYPE_FEEDBACK,
                                       index);

Loading