L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
port_ixl.h
1/*
2 * Copyright (C) 2024 Kernkonzept GmbH.
3 * Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
4 *
5 * License: see LICENSE.spdx (in this directory or the directories above)
6 */
7#pragma once
8
9#include "port.h"
10#include "request_ixl.h"
11
12#include <l4/ixl/device.h>
13#include <l4/ixl/memory.h>
14
15#include <optional>
16
22class Ixl_port : public Port_iface
23{
24public:
25 static constexpr unsigned Tx_batch_size = 32;
26 static constexpr unsigned Num_bufs = 1024;
27 static constexpr unsigned Buf_size = 2048;
28 static constexpr l4_uint64_t Max_mem_size = 1ULL << 28;
29
30 Ixl_port(Ixl::Ixl_device *dev)
31 : Port_iface(dev->get_driver_name().c_str()),
32 _dev(dev),
33 _mempool(*_dev, Num_bufs, Buf_size, Max_mem_size)
34 {
35 Ixl::mac_address mac_addr = _dev->get_mac_addr();
36 _mac = Mac_addr(reinterpret_cast<char const *>(mac_addr.addr));
37#if CONFIG_VNS_STATS
38 _mac.to_array(_stats->mac);
39#endif
40 }
41
42 // OPTIMIZE: Could use this information for rx batching, i.e. collect while
43 // rx_notify is disabled, then flush the collected buffers when
44 // rx_notify is enabled again.
45 void rx_notify_disable_and_remember() override {}
46 void rx_notify_emit_and_enable() override {}
47 bool is_gone() const override { return false; }
48
50 bool tx_work_pending()
51 {
52 fetch_tx_requests();
53 return _tx_batch_idx < _tx_batch_len;
54 }
55
57 std::optional<Ixl_net_request> get_tx_request()
58 {
59 fetch_tx_requests();
60 if (_tx_batch_idx < _tx_batch_len)
61 return std::make_optional<Ixl_net_request>(_tx_batch[_tx_batch_idx++]);
62 else
63 return std::nullopt;
64 }
65
66 Result handle_request(Port_iface *src_port, Net_transfer &src,
67 l4_uint64_t *bytes_transferred) override
68 {
69 Virtio_vlan_mangle mangle = create_vlan_mangle(src_port);
70
71 Dbg trace(Dbg::Request, Dbg::Trace, "REQ-IXL");
72 trace.printf("%s: Transfer request %p.\n", _name, src.req_id());
73
74 struct Ixl::pkt_buf *buf = _mempool.pkt_buf_alloc();
75 if (!buf)
76 {
77 trace.printf("\tTransfer failed, out-of-memory, dropping.\n");
78 return Result::Dropped;
79 }
80
81 // NOTE: Currently, the switch does not offer checksum or segmentation
82 // offloading to its l4virtio clients, so it is fine to simply ignore
83 // the Virtio_net::Hdr of the request here.
84
85 // Copy the request to the pkt_buf.
86 Buffer dst_buf(reinterpret_cast<char *>(buf->data),
87 Buf_size - offsetof(Ixl::pkt_buf, data));
88 unsigned max_size = Buf_size - offsetof(Ixl::pkt_buf, data);
89 for (;;)
90 {
91 try
92 {
93 if (src.done())
94 // Request completely copied to destination.
95 break;
96 }
98 {
99 trace.printf("\tTransfer failed, bad descriptor exception, dropping.\n");
100
101 // Handle partial transfers to destination port.
102 Ixl::pkt_buf_free(buf);
103 throw;
104 }
105
106 if (dst_buf.done())
107 {
108 trace.printf(
109 "\tTransfer failed, exceeds max packet-size, dropping.\n");
110 Ixl::pkt_buf_free(buf);
111 return Result::Dropped;
112 }
113
114 auto &src_buf = src.cur_buf();
115 trace.printf("\tCopying %p#%p:%u (%x) -> %p#%p:%u (%x)\n",
116 src_port, src_buf.pos, src_buf.left, src_buf.left,
117 static_cast<Port_iface *>(this),
118 dst_buf.pos, dst_buf.left, dst_buf.left);
119
120 mangle.copy_pkt(dst_buf, src_buf);
121 }
122 buf->size = max_size - dst_buf.left;
123 *bytes_transferred = buf->size;
124
125 // Enqueue the pkt_buf at the device.
126 if (_dev->tx_batch(0, &buf, 1) == 1)
127 {
128 trace.printf("\tTransfer queued at device.\n");
129 return Result::Delivered;
130 }
131 else
132 {
133 trace.printf("\tTransfer failed, dropping.\n");
134 Ixl::pkt_buf_free(buf);
135 return Result::Dropped;
136 }
137 }
138
139 Ixl::Ixl_device *dev() { return _dev; }
140
141private:
142 void fetch_tx_requests()
143 {
144 if (_tx_batch_idx < _tx_batch_len)
145 // Previous batch not yet fully processed.
146 return;
147
148 // Batch receive, then cache in member array, to avoid frequent interactions
149 // with the hardware.
150 _tx_batch_len = _dev->rx_batch(0, _tx_batch, Tx_batch_size);
151 _tx_batch_idx = 0;
152 }
153
154 Ixl::Ixl_device *_dev;
155 Ixl::Mempool _mempool;
156 Ixl::pkt_buf *_tx_batch[Tx_batch_size];
157 unsigned _tx_batch_idx = 0;
158 unsigned _tx_batch_len = 0;
159};
160
A wrapper class around the value of a MAC address.
Definition mac_addr.h:20
A network request to only a single destination.
Definition request.h:34
void const * req_id() const
Identifier for the underlying Net_request, used for logging purposes.
Definition request.h:41
virtual bool done()=0
Check whether the transfer has been completed, i.e.
Buffer & cur_buf()
Buffer containing (a part of) the packet data.
Definition request.h:54
Class for VLAN packet rewriting.
Definition vlan.h:37
l4_uint32_t copy_pkt(Buffer &dst, Buffer &src)
Copy packet from src to dst.
Definition vlan.h:93
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:31
Data buffer used to transfer packets.
Exception used by Queue to indicate descriptor errors.
Definition virtio:398