From ae88eb52f7bba9132a7b911be3a319204d477f99 Mon Sep 17 00:00:00 2001 From: Harvey Tuch Date: Mon, 26 Mar 2018 14:12:55 -0400 Subject: [PATCH] socket: IP_FREEBIND support for listeners and upstream connections. This patch introduces support for setting IP_FREEBIND on both listener sockets and upstream connection sockets prior to binding. This enables the use of IP addresses that are not currently bound to the NIC for listening and initiating connections from. This is useful in environments with virtualized networking. There's also some related work on SocketOption that continues from #2734, which was needed to enable this to work cleanly. Risk Level: Low (no change unless enabled). Testing: Unit tests for ListenerManager, ClusterManager and SocketOptionImpl. Manual end-to-end validation with steps described in configs/freebind/README.md. API Changes: https://github.com/envoyproxy/data-plane-api/pull/536 Fixes #528. Signed-off-by: Harvey Tuch --- bazel/repository_locations.bzl | 2 +- configs/freebind/README.md | 14 ++ configs/freebind/freebind.yaml | 41 +++++ include/envoy/api/os_sys_calls.h | 11 ++ include/envoy/network/listen_socket.h | 7 +- include/envoy/server/filter_config.h | 2 +- include/envoy/upstream/cluster_manager.h | 8 +- include/envoy/upstream/upstream.h | 2 + source/common/api/os_sys_calls_impl.cc | 10 ++ source/common/api/os_sys_calls_impl.h | 2 + source/common/network/BUILD | 14 ++ source/common/network/listen_socket_impl.cc | 1 + source/common/network/listen_socket_impl.h | 4 +- source/common/network/socket_option_impl.cc | 80 +++++++++ source/common/network/socket_option_impl.h | 64 +++++++ source/common/upstream/BUILD | 1 + .../common/upstream/cluster_manager_impl.cc | 8 +- source/common/upstream/cluster_manager_impl.h | 6 +- source/common/upstream/eds.cc | 2 +- source/common/upstream/logical_dns_cluster.cc | 3 +- .../common/upstream/original_dst_cluster.cc | 3 +- source/common/upstream/upstream_impl.cc | 73 +++++--- source/common/upstream/upstream_impl.h | 14 +- source/server/BUILD | 1 + source/server/listener_manager_impl.cc | 14 ++ source/server/listener_manager_impl.h | 5 +- test/common/network/BUILD | 12 ++ .../common/network/listen_socket_impl_test.cc | 4 +- test/common/network/listener_impl_test.cc | 2 +- .../common/network/socket_option_impl_test.cc | 166 ++++++++++++++++++ test/common/upstream/BUILD | 3 + .../upstream/cluster_manager_impl_test.cc | 153 ++++++++++++++++ test/common/upstream/upstream_impl_test.cc | 8 +- test/mocks/api/BUILD | 1 + test/mocks/api/mocks.cc | 31 ++++ test/mocks/api/mocks.h | 9 + test/mocks/network/mocks.h | 8 +- test/mocks/server/mocks.h | 4 +- test/mocks/upstream/mocks.cc | 2 +- test/mocks/upstream/mocks.h | 4 +- test/server/BUILD | 3 + test/server/listener_manager_impl_test.cc | 73 ++++++++ 42 files changed, 799 insertions(+), 76 deletions(-) create mode 100644 configs/freebind/README.md create mode 100644 configs/freebind/freebind.yaml create mode 100644 source/common/network/socket_option_impl.cc create mode 100644 source/common/network/socket_option_impl.h create mode 100644 test/common/network/socket_option_impl_test.cc diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index d7a76aee8240..f8e276a1ebc6 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -76,7 +76,7 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/google/protobuf/archive/v3.5.0.tar.gz"], ), envoy_api = dict( - commit = "e73b8264a26c909f75d38ec2c73d9f47ad1b3b57", + commit = "ec157d3d8b359a1bd65c22116ba4387a459cc53a", remote = "https://github.com/envoyproxy/data-plane-api", ), grpc_httpjson_transcoding = dict( diff --git a/configs/freebind/README.md b/configs/freebind/README.md new file mode 100644 index 000000000000..9e479c0753eb --- /dev/null +++ b/configs/freebind/README.md @@ -0,0 +1,14 @@ +# Freebind testing + +To manually validate the `IP_FREEBIND` behavior in Envoy, you can launch Envoy with +[freebind.yaml](freebind.yaml). + +The listener free bind behavior can be verified with: + +1. `envoy -c ./configs/freebind/freebind.yaml -l trace` +2. `sudo ifconfig lo:1 192.168.42.1/30 up` +3. `nc -v -l 0.0.0.0 10001` + +To cleanup run `sudo ifconfig lo:1 down`. + +TODO(htuch): Steps to verify upstream behavior. diff --git a/configs/freebind/freebind.yaml b/configs/freebind/freebind.yaml new file mode 100644 index 000000000000..9b494bd05742 --- /dev/null +++ b/configs/freebind/freebind.yaml @@ -0,0 +1,41 @@ +admin: + access_log_path: /tmp/admin_access.log + address: + socket_address: { address: 127.0.0.1, port_value: 9901 } + +static_resources: + listeners: + - name: listener_0 + address: + socket_address: { address: 192.168.42.1, port_value: 10000 } + freebind: true + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: ["*"] + routes: + - match: { prefix: "/" } + route: { cluster: service_local } + http_filters: + - name: envoy.router + clusters: + - name: service_local + connect_timeout: 30s + type: STATIC + lb_policy: ROUND_ROBIN + hosts: + - socket_address: + address: 127.0.0.1 + port_value: 10001 +# TODO(htuch): Figure out how to do end-to-end testing with +# outgoing connections and free bind. +# upstream_bind_config: +# source_address: +# address: 192.168.43.1 +# freebind: true diff --git a/include/envoy/api/os_sys_calls.h b/include/envoy/api/os_sys_calls.h index 9843352ac569..ee5d4d6b7999 100644 --- a/include/envoy/api/os_sys_calls.h +++ b/include/envoy/api/os_sys_calls.h @@ -63,6 +63,17 @@ class OsSysCalls { * @see man 2 stat */ virtual int stat(const char* pathname, struct stat* buf) PURE; + + /** + * @see man 2 setsockopt + */ + virtual int setsockopt(int sockfd, int level, int optname, const void* optval, + socklen_t optlen) PURE; + + /** + * @see man 2 getsockopt + */ + virtual int getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen) PURE; }; typedef std::unique_ptr OsSysCallsPtr; diff --git a/include/envoy/network/listen_socket.h b/include/envoy/network/listen_socket.h index b8ba4700ee75..9a5a320b2d59 100644 --- a/include/envoy/network/listen_socket.h +++ b/include/envoy/network/listen_socket.h @@ -55,13 +55,14 @@ class Socket { */ virtual void hashKey(std::vector& key) const PURE; }; - typedef std::unique_ptr