1
#pragma once
2

            
3
#include <cstdint>
4
#include <memory>
5

            
6
#include "envoy/http/codec.h"
7
#include "envoy/tcp/conn_pool.h"
8
#include "envoy/upstream/thread_local_cluster.h"
9

            
10
#include "source/common/buffer/watermark_buffer.h"
11
#include "source/common/common/cleanup.h"
12
#include "source/common/common/logger.h"
13
#include "source/common/config/well_known_names.h"
14
#include "source/common/network/utility.h"
15
#include "source/common/router/upstream_request.h"
16
#include "source/common/stream_info/stream_info_impl.h"
17

            
18
#include "quiche/common/capsule.h"
19
#include "quiche/common/simple_buffer_allocator.h"
20

            
21
namespace Envoy {
22
namespace Extensions {
23
namespace Upstreams {
24
namespace Http {
25
namespace Udp {
26

            
27
// Creates a UDP socket for a UDP upstream connection. When a new UDP upstream is requested by the
28
// UpstreamRequest of Router, creates a UDPUpstream object and hands over the created socket to it.
29
class UdpConnPool : public Router::GenericConnPool {
30
public:
31
39
  UdpConnPool(Upstream::HostConstSharedPtr host) : host_(host) {}
32

            
33
  // Creates a UDPUpstream object for a new stream.
34
  void newStream(Router::GenericConnectionPoolCallbacks* callbacks) override;
35

            
36
32
  bool cancelAnyPendingStream() override {
37
    // Unlike TCP, UDP Upstreams do not have any pending streams because the upstream connection is
38
    // created immediately without a handshake.
39
32
    return false;
40
32
  }
41

            
42
64
  Upstream::HostDescriptionConstSharedPtr host() const override { return host_; }
43

            
44
36
  Network::SocketPtr createSocket(const Upstream::HostConstSharedPtr& host) {
45
36
    const Network::Address::InstanceConstSharedPtr& host_address = host->address();
46
36
    auto ret = std::make_unique<Network::SocketImpl>(Network::Socket::Type::Datagram,
47
36
                                                     /*address_for_io_handle=*/host_address,
48
36
                                                     /*remote_address=*/host_address,
49
36
                                                     Network::SocketCreationOptions{});
50
36
    RELEASE_ASSERT(ret->isOpen(), "Socket creation fail");
51
36
    return ret;
52
36
  }
53

            
54
35
  bool valid() const override { return host_ != nullptr; }
55

            
56
private:
57
  Upstream::HostConstSharedPtr host_;
58
};
59

            
60
// Maintains data relevant to a UDP upstream connection including the socket for the upstream.
61
// When a CONNECT-UDP request comes in, connects the socket to a node in the upstream cluster.
62
// Also, adds appropriate header entries to the CONNECT-UDP response.
63
class UdpUpstream : public Router::GenericUpstream,
64
                    public Network::UdpPacketProcessor,
65
                    public quiche::CapsuleParser::Visitor {
66
public:
67
  UdpUpstream(Router::UpstreamToDownstream* upstream_to_downstream, Network::SocketPtr socket,
68
              Upstream::HostConstSharedPtr host, Event::Dispatcher& dispatcher);
69

            
70
  // GenericUpstream
71
  void encodeData(Buffer::Instance& data, bool end_stream) override;
72
1
  void encodeMetadata(const Envoy::Http::MetadataMapVector&) override {}
73
  Envoy::Http::Status encodeHeaders(const Envoy::Http::RequestHeaderMap&, bool end_stream) override;
74
1
  void encodeTrailers(const Envoy::Http::RequestTrailerMap&) override {}
75
1
  void readDisable(bool) override {}
76
  void resetStream() override;
77
9
  void enableTcpTunneling() override {}
78
32
  void setAccount(Buffer::BufferMemoryAccountSharedPtr) override {}
79
32
  const StreamInfo::BytesMeterSharedPtr& bytesMeter() override { return bytes_meter_; }
80

            
81
  // Network::UdpPacketProcessor
82
  // Handles data received from the UDP Upstream.
83
  void processPacket(Network::Address::InstanceConstSharedPtr local_address,
84
                     Network::Address::InstanceConstSharedPtr peer_address,
85
                     Buffer::InstancePtr buffer, MonotonicTime receive_time, uint8_t tos,
86
                     Buffer::OwnedImpl saved_cmsg) override;
87
  uint64_t maxDatagramSize() const override { return Network::DEFAULT_UDP_MAX_DATAGRAM_SIZE; }
88
2
  void onDatagramsDropped(uint32_t dropped) override {
89
    // TODO(https://github.com/envoyproxy/envoy/issues/23564): Add statistics for CONNECT-UDP
90
    // upstreams.
91
2
    ENVOY_LOG_MISC(warn, "{} UDP datagrams were dropped.", dropped);
92
2
    datagrams_dropped_ += dropped;
93
2
  }
94
16
  size_t numPacketsExpectedPerEventLoop() const override {
95
16
    return Network::MAX_NUM_PACKETS_PER_EVENT_LOOP;
96
16
  }
97
2
  uint32_t numOfDroppedDatagrams() { return datagrams_dropped_; }
98
32
  const Network::IoHandle::UdpSaveCmsgConfig& saveCmsgConfig() const override {
99
32
    static const Network::IoHandle::UdpSaveCmsgConfig empty_config{};
100
32
    return empty_config;
101
32
  };
102

            
103
  // quiche::CapsuleParser::Visitor
104
  bool OnCapsule(const quiche::Capsule& capsule) override;
105
  void OnCapsuleParseFailure(absl::string_view error_message) override;
106

            
107
private:
108
  void onSocketReadReady();
109

            
110
  Router::UpstreamToDownstream* upstream_to_downstream_;
111
  const Network::SocketPtr socket_;
112
  Upstream::HostConstSharedPtr host_;
113
  Event::Dispatcher& dispatcher_;
114
  StreamInfo::BytesMeterSharedPtr bytes_meter_{std::make_shared<StreamInfo::BytesMeter>()};
115
  quiche::CapsuleParser capsule_parser_{this};
116
  quiche::SimpleBufferAllocator capsule_buffer_allocator_;
117
  uint32_t datagrams_dropped_ = 0;
118
};
119

            
120
} // namespace Udp
121
} // namespace Http
122
} // namespace Upstreams
123
} // namespace Extensions
124
} // namespace Envoy