aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/include/uhdlib/transport/dpdk/udp.hpp
blob: 712b73d814e897ffdb41caf4a2d67e7b658309d5 (plain)
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//
// Copyright 2019 Ettus Research, a National Instruments brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#pragma once

#include <uhdlib/transport/dpdk/common.hpp>
#include <arpa/inet.h>
#include <netinet/udp.h>
#include <rte_ip.h>
#include <rte_udp.h>
#include <boost/format.hpp>

namespace uhd { namespace transport { namespace dpdk {

constexpr size_t HDR_SIZE_UDP_IPV4 =
    (sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_udp_hdr));

/*!
 * An enumerated type representing the type of flow for an IPv4 client
 * Currently, only UDP is supported (FLOW_TYPE_UDP)
 */
enum flow_type {
    FLOW_TYPE_UDP,
    FLOW_TYPE_COUNT,
};

/*!
 * A tuple for IPv4 flows that can be used for hashing
 */
struct ipv4_5tuple
{
    enum flow_type flow_type;
    rte_ipv4_addr src_ip;
    rte_ipv4_addr dst_ip;
    uint16_t src_port;
    uint16_t dst_port;
};

inline void fill_rte_ipv4_hdr(struct rte_mbuf* mbuf,
    const dpdk_port* port,
    uint32_t dst_rte_ipv4_addr,
    uint8_t proto_id,
    uint32_t payload_len)
{
    struct rte_ether_hdr* eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
    struct rte_ipv4_hdr* ip_hdr   = (struct rte_ipv4_hdr*)&eth_hdr[1];

    ip_hdr->version_ihl     = 0x40 | 5;
    ip_hdr->type_of_service = 0;
    ip_hdr->total_length    = rte_cpu_to_be_16(20 + payload_len);
    ip_hdr->packet_id       = 0;
    ip_hdr->fragment_offset = rte_cpu_to_be_16(RTE_IPV4_HDR_DF_FLAG);
    ip_hdr->time_to_live    = 64;
    ip_hdr->next_proto_id   = proto_id;
    ip_hdr->hdr_checksum    = 0; // Require HW offload
    ip_hdr->src_addr        = port->get_ipv4();
    ip_hdr->dst_addr        = dst_rte_ipv4_addr;

    mbuf->ol_flags = PKT_TX_IP_CKSUM | PKT_TX_IPV4;
    mbuf->l2_len   = sizeof(struct rte_ether_hdr);
    mbuf->l3_len   = sizeof(struct rte_ipv4_hdr);
    mbuf->pkt_len  = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + payload_len;
    mbuf->data_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + payload_len;
}

/* All values except payload length must be in network order */
inline void fill_rte_udp_hdr(struct rte_mbuf* mbuf,
    const dpdk_port* port,
    uint32_t dst_rte_ipv4_addr,
    uint16_t src_port,
    uint16_t dst_port,
    uint32_t payload_len)
{
    struct rte_ether_hdr* eth_hdr;
    struct rte_ipv4_hdr* ip_hdr;
    struct rte_udp_hdr* tx_hdr;

    fill_rte_ipv4_hdr(
        mbuf, port, dst_rte_ipv4_addr, IPPROTO_UDP, sizeof(struct rte_udp_hdr) + payload_len);

    eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
    ip_hdr  = (struct rte_ipv4_hdr*)&eth_hdr[1];
    tx_hdr  = (struct rte_udp_hdr*)&ip_hdr[1];

    tx_hdr->src_port    = src_port;
    tx_hdr->dst_port    = dst_port;
    tx_hdr->dgram_len   = rte_cpu_to_be_16(8 + payload_len);
    tx_hdr->dgram_cksum = 0;
    mbuf->l4_len        = sizeof(struct rte_udp_hdr);
}

//! Return an IPv4 address (numeric, in network order) into a string
inline std::string ipv4_num_to_str(const uint32_t ip_addr)
{
    char addr_str[INET_ADDRSTRLEN];
    struct in_addr rte_ipv4_addr;
    rte_ipv4_addr.s_addr = ip_addr;
    inet_ntop(AF_INET, &rte_ipv4_addr, addr_str, sizeof(addr_str));
    return std::string(addr_str);
}

inline std::string eth_addr_to_string(const struct rte_ether_addr mac_addr)
{
    auto mac_stream = boost::format("%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx");
    mac_stream % (uint32_t)mac_addr.addr_bytes[0] % (uint32_t)mac_addr.addr_bytes[1]
        % (uint32_t)mac_addr.addr_bytes[2] % (uint32_t)mac_addr.addr_bytes[3]
        % (uint32_t)mac_addr.addr_bytes[4] % (uint32_t)mac_addr.addr_bytes[5];
    return mac_stream.str();
}

}}} /* namespace uhd::transport::dpdk */