]>
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>
30 namespace ipv4_udp_impl
{
34 to_ipv4_addr(ipv4_address a
, uint16_t port
) {
38 class native_datagram
: public udp_datagram_impl
{
44 native_datagram(ipv4_address src
, ipv4_address dst
, packet p
)
46 udp_hdr
* hdr
= _p
.get_header
<udp_hdr
>();
48 _p
.trim_front(sizeof(*hdr
));
49 _src
= to_ipv4_addr(src
, h
.src_port
);
50 _dst
= to_ipv4_addr(dst
, h
.dst_port
);
53 virtual ipv4_addr
get_src() override
{
57 virtual ipv4_addr
get_dst() override
{
61 virtual uint16_t get_dst_port() override
{
65 virtual packet
& get_data() override
{
70 class native_channel
: public udp_channel_impl
{
73 ipv4_udp::registration _reg
;
75 lw_shared_ptr
<udp_channel_state
> _state
;
78 native_channel(ipv4_udp
&proto
, ipv4_udp::registration reg
, lw_shared_ptr
<udp_channel_state
> state
)
92 virtual future
<udp_datagram
> receive() override
{
93 return _state
->_queue
.pop_eventually();
96 virtual future
<> send(ipv4_addr dst
, const char* msg
) override
{
97 return send(dst
, packet::from_static_data(msg
, strlen(msg
)));
100 virtual future
<> send(ipv4_addr dst
, packet p
) override
{
102 return _state
->wait_for_send_buffer(len
).then([this, dst
, p
= std::move(p
), len
] () mutable {
103 p
= packet(std::move(p
), make_deleter([s
= _state
, len
] { s
->complete_send(len
); }));
104 _proto
.send(_reg
.port(), dst
, std::move(p
));
108 virtual bool is_closed() const override
{
112 virtual void shutdown_input() override
{
113 _state
->_queue
.abort(std::make_exception_ptr(std::system_error(EBADF
, std::system_category())));
116 virtual void shutdown_output() override
{
117 _state
->_queue
.abort(std::make_exception_ptr(std::system_error(EPIPE
, std::system_category())));
120 virtual void close() override
{
126 } /* namespace ipv4_udp_impl */
128 using namespace net::ipv4_udp_impl
;
130 const int ipv4_udp::default_queue_size
= 1024;
132 ipv4_udp::ipv4_udp(ipv4
& inet
)
135 _inet
.register_packet_provider([this] {
136 compat::optional
<ipv4_traits::l4packet
> l4p
;
137 if (!_packetq
.empty()) {
138 l4p
= std::move(_packetq
.front());
139 _packetq
.pop_front();
145 bool ipv4_udp::forward(forward_hash
& out_hash_data
, packet
& p
, size_t off
)
147 auto uh
= p
.get_header
<udp_hdr
>(off
);
150 out_hash_data
.push_back(uh
->src_port
);
151 out_hash_data
.push_back(uh
->dst_port
);
156 void ipv4_udp::received(packet p
, ipv4_address from
, ipv4_address to
)
158 udp_datagram
dgram(std::make_unique
<native_datagram
>(from
, to
, std::move(p
)));
160 auto chan_it
= _channels
.find(dgram
.get_dst_port());
161 if (chan_it
!= _channels
.end()) {
162 auto chan
= chan_it
->second
;
163 chan
->_queue
.push(std::move(dgram
));
167 void ipv4_udp::send(uint16_t src_port
, ipv4_addr dst
, packet
&&p
)
169 auto src
= _inet
.host_address();
170 auto hdr
= p
.prepend_header
<udp_hdr
>();
171 hdr
->src_port
= src_port
;
172 hdr
->dst_port
= dst
.port
;
178 ipv4_traits::udp_pseudo_header_checksum(csum
, src
, dst
, p
.len());
179 bool needs_frag
= ipv4::needs_frag(p
, ip_protocol_num::udp
, _inet
.hw_features());
180 if (_inet
.hw_features().tx_csum_l4_offload
&& !needs_frag
) {
181 hdr
->cksum
= ~csum
.get();
182 oi
.needs_csum
= true;
185 hdr
->cksum
= csum
.get();
186 oi
.needs_csum
= false;
188 oi
.protocol
= ip_protocol_num::udp
;
189 p
.set_offload_info(oi
);
191 _inet
.get_l2_dst_address(dst
).then([this, dst
, p
= std::move(p
)] (ethernet_address e_dst
) mutable {
192 _packetq
.emplace_back(ipv4_traits::l4packet
{dst
, std::move(p
), e_dst
, ip_protocol_num::udp
});
196 uint16_t ipv4_udp::next_port(uint16_t port
) {
197 return (port
+ 1) == 0 ? min_anonymous_port
: port
+ 1;
201 ipv4_udp::make_channel(ipv4_addr addr
) {
202 if (!is_ip_unspecified(addr
)) {
203 throw std::runtime_error("Binding to specific IP not supported yet");
208 if (!is_port_unspecified(addr
)) {
209 if (_channels
.count(addr
.port
)) {
210 throw std::runtime_error("Address already in use");
212 bind_port
= addr
.port
;
214 auto starting_port
= _next_anonymous_port
;
215 while (_channels
.count(_next_anonymous_port
)) {
216 _next_anonymous_port
= next_port(_next_anonymous_port
);
217 if (starting_port
== _next_anonymous_port
) {
218 throw std::runtime_error("No free port");
222 bind_port
= _next_anonymous_port
;
223 _next_anonymous_port
= next_port(_next_anonymous_port
);
226 auto chan_state
= make_lw_shared
<udp_channel_state
>(_queue_size
);
227 _channels
[bind_port
] = chan_state
;
228 return udp_channel(std::make_unique
<native_channel
>(*this, registration(*this, bind_port
), chan_state
));
231 } /* namespace net */