summaryrefslogtreecommitdiff
path: root/src/mpu.h
blob: da41a255e6523273ca6abcac1338724974d279f0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* SPDX-License-Identifier: GPL-3.0-or-later */

#pragma once

#include "heap.h"

#include <netinet/in.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>

//
// A two-path UDP tunnel implementation.
//
// The tunnel uses two physical paths to transmit packets to the same destination.
//
// Sent packets are assigned a sequence number and transmitted through one of the
// two paths according to a weighted round-robin scheduler.
//
// On the receiving end, packets are buffered in a reorder buffer and a best effort is made
// to deliver packets in order.
//

#define MPU_MTU (1500U - 20 - 8) //!< Maximum payload size for traditional IP/UDP headers

typedef struct {
    int sockfd;
    float weight;
} mpu_path_t; //!< Physical path for packet transmission

typedef struct {
    uint64_t seq_num;
} mpu_hdr_t; //!< Tunnel packet header

typedef struct {
    uint64_t timestamp; // in milliseconds
    uint16_t packet_len;
    union {
        uint8_t buf[MPU_MTU];
        mpu_hdr_t hdr;
    } packet;
} mpu_slot_t; //!< Packet slot for reorder buffer

typedef struct {
    mpu_path_t paths[2];

    // Weighted round-robin scheduler state
    float credits[2];
    uint64_t send_seq_num;

    // Reorder buffer
    uint64_t recv_seq_num;
    int reorder_window; // in milliseconds
    heap_t reorder_heap;
} mpu_ctx_t;

/// Initialize MPU context with two physical paths
/// Returns 0 on success, -1 on failure (errno is set).
int mpu_init(mpu_ctx_t* ctx,
    int sock0, float weight0,
    int sock1, float weight1,
    int reorder_window, // in milliseconds
    size_t reorder_slots);

/// Send a packet through the tunnel. Packet must not exceed MPU_MTU - sizeof(mpu_hdr_t).
/// Returns 0 on success, -1 on failure (errno is set).
int mpu_send(mpu_ctx_t* ctx, const uint8_t* data, size_t len);

/// Receive a packet from the tunnel, blocking until one is available.
/// Returns the length of the received data, or -1 on failure (errno is set).
ssize_t mpu_recv(mpu_ctx_t* ctx, uint8_t* data, size_t len);