]>
git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/src/net/udp.cc
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
22 #include <seastar/net/ip.hh>
23 #include <seastar/net/stack.hh>
24 #include <seastar/net/inet_address.hh>
31 namespace ipv4_udp_impl
{
35 to_ipv4_addr(ipv4_address a
, uint16_t port
) {
39 class native_datagram
: public udp_datagram_impl
{
45 native_datagram(ipv4_address src
, ipv4_address dst
, packet p
)
47 udp_hdr
* hdr
= _p
.get_header
<udp_hdr
>();
49 _p
.trim_front(sizeof(*hdr
));
50 _src
= to_ipv4_addr(src
, h
.src_port
);
51 _dst
= to_ipv4_addr(dst
, h
.dst_port
);
54 virtual socket_address
get_src() override
{
58 virtual socket_address
get_dst() override
{
62 virtual uint16_t get_dst_port() override
{
66 virtual packet
& get_data() override
{
71 class native_channel
: public udp_channel_impl
{
74 ipv4_udp::registration _reg
;
76 lw_shared_ptr
<udp_channel_state
> _state
;
79 native_channel(ipv4_udp
&proto
, ipv4_udp::registration reg
, lw_shared_ptr
<udp_channel_state
> state
)
93 socket_address
local_address() const override
{
94 return socket_address(_proto
.inet().host_address(), _reg
.port());
97 virtual future
<udp_datagram
> receive() override
{
98 return _state
->_queue
.pop_eventually();
101 virtual future
<> send(const socket_address
& dst
, const char* msg
) override
{
102 return send(dst
, packet::from_static_data(msg
, strlen(msg
)));
105 virtual future
<> send(const socket_address
& dst
, packet p
) override
{
107 return _state
->wait_for_send_buffer(len
).then([this, dst
, p
= std::move(p
), len
] () mutable {
108 p
= packet(std::move(p
), make_deleter([s
= _state
, len
] { s
->complete_send(len
); }));
109 _proto
.send(_reg
.port(), dst
, std::move(p
));
113 virtual bool is_closed() const override
{
117 virtual void shutdown_input() override
{
118 _state
->_queue
.abort(std::make_exception_ptr(std::system_error(EBADF
, std::system_category())));
121 virtual void shutdown_output() override
{
122 _state
->_queue
.abort(std::make_exception_ptr(std::system_error(EPIPE
, std::system_category())));
125 virtual void close() override
{
131 } /* namespace ipv4_udp_impl */
133 using namespace net::ipv4_udp_impl
;
135 const int ipv4_udp::default_queue_size
= 1024;
137 ipv4_udp::ipv4_udp(ipv4
& inet
)
140 _inet
.register_packet_provider([this] {
141 std::optional
<ipv4_traits::l4packet
> l4p
;
142 if (!_packetq
.empty()) {
143 l4p
= std::move(_packetq
.front());
144 _packetq
.pop_front();
150 bool ipv4_udp::forward(forward_hash
& out_hash_data
, packet
& p
, size_t off
)
152 auto uh
= p
.get_header
<udp_hdr
>(off
);
155 out_hash_data
.push_back(uh
->src_port
);
156 out_hash_data
.push_back(uh
->dst_port
);
161 void ipv4_udp::received(packet p
, ipv4_address from
, ipv4_address to
)
163 udp_datagram
dgram(std::make_unique
<native_datagram
>(from
, to
, std::move(p
)));
165 auto chan_it
= _channels
.find(dgram
.get_dst_port());
166 if (chan_it
!= _channels
.end()) {
167 auto chan
= chan_it
->second
;
168 chan
->_queue
.push(std::move(dgram
));
172 void ipv4_udp::send(uint16_t src_port
, ipv4_addr dst
, packet
&&p
)
174 auto src
= _inet
.host_address();
175 auto hdr
= p
.prepend_header
<udp_hdr
>();
176 hdr
->src_port
= src_port
;
177 hdr
->dst_port
= dst
.port
;
183 ipv4_traits::udp_pseudo_header_checksum(csum
, src
, dst
, p
.len());
184 bool needs_frag
= ipv4::needs_frag(p
, ip_protocol_num::udp
, _inet
.hw_features());
185 if (_inet
.hw_features().tx_csum_l4_offload
&& !needs_frag
) {
186 hdr
->cksum
= ~csum
.get();
187 oi
.needs_csum
= true;
190 hdr
->cksum
= csum
.get();
191 oi
.needs_csum
= false;
193 oi
.protocol
= ip_protocol_num::udp
;
194 p
.set_offload_info(oi
);
196 // FIXME: future is discarded
197 (void)_inet
.get_l2_dst_address(dst
).then([this, dst
, p
= std::move(p
)] (ethernet_address e_dst
) mutable {
198 _packetq
.emplace_back(ipv4_traits::l4packet
{dst
, std::move(p
), e_dst
, ip_protocol_num::udp
});
202 uint16_t ipv4_udp::next_port(uint16_t port
) {
203 return (port
+ 1) == 0 ? min_anonymous_port
: port
+ 1;
207 ipv4_udp::make_channel(ipv4_addr addr
) {
208 if (!is_ip_unspecified(addr
)) {
209 throw std::runtime_error("Binding to specific IP not supported yet");
214 if (!is_port_unspecified(addr
)) {
215 if (_channels
.count(addr
.port
)) {
216 throw std::runtime_error("Address already in use");
218 bind_port
= addr
.port
;
220 auto starting_port
= _next_anonymous_port
;
221 while (_channels
.count(_next_anonymous_port
)) {
222 _next_anonymous_port
= next_port(_next_anonymous_port
);
223 if (starting_port
== _next_anonymous_port
) {
224 throw std::runtime_error("No free port");
228 bind_port
= _next_anonymous_port
;
229 _next_anonymous_port
= next_port(_next_anonymous_port
);
232 auto chan_state
= make_lw_shared
<udp_channel_state
>(_queue_size
);
233 _channels
[bind_port
] = chan_state
;
234 return udp_channel(std::make_unique
<native_channel
>(*this, registration(*this, bind_port
), chan_state
));
237 } /* namespace net */