Repository: mesos Updated Branches: refs/heads/master 896ec461e -> 5d46ce9b1
Added support for getting socket diagnosis information. Review: https://reviews.apache.org/r/25948 Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/5d46ce9b Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/5d46ce9b Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/5d46ce9b Branch: refs/heads/master Commit: 5d46ce9b1df0de14caaf803bdb8a335dce98e58a Parents: 896ec46 Author: Chi Zhang <[email protected]> Authored: Wed Sep 24 10:44:38 2014 -0700 Committer: Jie Yu <[email protected]> Committed: Wed Sep 24 10:53:18 2014 -0700 ---------------------------------------------------------------------- configure.ac | 11 +++ src/Makefile.am | 2 + src/linux/routing/diagnosis/diagnosis.cpp | 87 ++++++++++++++++++ src/linux/routing/diagnosis/diagnosis.hpp | 121 +++++++++++++++++++++++++ src/linux/routing/internal.hpp | 14 ++- src/tests/routing_tests.cpp | 18 ++++ 6 files changed, 249 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/5d46ce9b/configure.ac ---------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index da61c29..86d448c 100644 --- a/configure.ac +++ b/configure.ac @@ -665,6 +665,17 @@ http://www.infradead.org/~tgr/libnl/ ------------------------------------------------------------------- ])]) + # Check for libnl-idiag-3 (both headers and libraries). + AC_CHECK_LIB([nl-idiag-3], [idiagnl_msg_alloc_cache], [], + [AC_MSG_ERROR([cannot find libnl-idiag-3 +------------------------------------------------------------------- +We need libnl-idiag-3 for building network isolator! + +Please install libnl3 (version 3.2.24 or higher): +http://www.infradead.org/~tgr/libnl/ +------------------------------------------------------------------- + ])]) + # TODO(jieyu): Automatically detect the location where the libnl # headers are installed. LIBNL_CFLAGS=-I/usr/include/libnl3 http://git-wip-us.apache.org/repos/asf/mesos/blob/5d46ce9b/src/Makefile.am ---------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index 9b973e5..b821a3b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -348,6 +348,7 @@ if WITH_NETWORK_ISOLATOR libmesos_no_3rdparty_la_SOURCES += \ linux/routing/route.cpp \ linux/routing/utils.cpp \ + linux/routing/diagnosis/diagnosis.cpp \ linux/routing/filter/arp.cpp \ linux/routing/filter/icmp.cpp \ linux/routing/filter/ip.cpp \ @@ -359,6 +360,7 @@ if WITH_NETWORK_ISOLATOR linux/routing/internal.hpp \ linux/routing/route.hpp \ linux/routing/utils.hpp \ + linux/routing/diagnosis/diagnosis.hpp \ linux/routing/filter/action.hpp \ linux/routing/filter/arp.hpp \ linux/routing/filter/filter.hpp \ http://git-wip-us.apache.org/repos/asf/mesos/blob/5d46ce9b/src/linux/routing/diagnosis/diagnosis.cpp ---------------------------------------------------------------------- diff --git a/src/linux/routing/diagnosis/diagnosis.cpp b/src/linux/routing/diagnosis/diagnosis.cpp new file mode 100644 index 0000000..36e4e2d --- /dev/null +++ b/src/linux/routing/diagnosis/diagnosis.cpp @@ -0,0 +1,87 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <netlink/cache.h> +#include <netlink/errno.h> + +#include <netlink/idiag/msg.h> + +#include <stout/error.hpp> +#include <stout/try.hpp> + +#include "linux/routing/internal.hpp" + +#include "linux/routing/diagnosis/diagnosis.hpp" + +using namespace std; + +namespace routing { +namespace diagnosis { + +namespace socket { + +static Option<net::IP> IP(nl_addr* _ip) +{ + Option<net::IP> result; + if (_ip != NULL && nl_addr_get_len(_ip) != 0) { + struct in_addr* addr = (struct in_addr*) nl_addr_get_binary_addr(_ip); + + result = net::IP(ntohl(addr->s_addr)); + } + + return result; +} + + +Try<vector<Info> > infos(int family, State states) +{ + Try<Netlink<struct nl_sock> > sock = routing::socket(NETLINK_INET_DIAG); + if (sock.isError()) { + return Error(sock.error()); + } + + struct nl_cache* c = NULL; + int err = idiagnl_msg_alloc_cache(sock.get().get(), family, states, &c); + if (err != 0) { + return Error(nl_geterror(err)); + } + + Netlink<struct nl_cache> cache(c); + + vector<Info> results; + for (struct nl_object* o = nl_cache_get_first(cache.get()); + o != NULL; o = nl_cache_get_next(o)) { + struct idiagnl_msg* msg = (struct idiagnl_msg*)o; + + results.push_back(Info( + idiagnl_msg_get_family(msg), + (State) idiagnl_msg_get_state(msg), + idiagnl_msg_get_sport(msg), + idiagnl_msg_get_dport(msg), + IP(idiagnl_msg_get_src(msg)), + IP(idiagnl_msg_get_dst(msg)), + idiagnl_msg_get_tcpinfo(msg))); + } + + return results; +} + +} // namespace socket { + +} // namespace diagnosis { +} // namespace routing { http://git-wip-us.apache.org/repos/asf/mesos/blob/5d46ce9b/src/linux/routing/diagnosis/diagnosis.hpp ---------------------------------------------------------------------- diff --git a/src/linux/routing/diagnosis/diagnosis.hpp b/src/linux/routing/diagnosis/diagnosis.hpp new file mode 100644 index 0000000..aa1b3a3 --- /dev/null +++ b/src/linux/routing/diagnosis/diagnosis.hpp @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LINUX_ROUTING_DIAGNOSIS_DIAGNOSIS_HPP__ +#define __LINUX_ROUTING_DIAGNOSIS_DIAGNOSIS_HPP__ + +#include <sys/socket.h> // For protocol families, e.g., AF_INET6 is IPv6. + +#include <netinet/tcp.h> // For tcp_info. + +#include <vector> + +#include <stout/net.hpp> +#include <stout/option.hpp> +#include <stout/try.hpp> + +namespace routing { +namespace diagnosis { + +namespace socket { + +// The connection state of a socket. +// TODO(chzhcn): libnl3-idiag still uses the old idiag kernel API, +// which only supports TCP sockets. When it moves to the newer API, +// consider changing this to a per-family state structure. +enum State +{ + UNKNOWN, + ESTABLISHED, + SYN_SENT, + SYN_RECV, + FIN_WAIT1, + FIN_WAIT2, + TIME_WAIT, + CLOSE, + CLOSE_WAIT, + LAST_ACK, + LISTEN, + CLOSING, + MAX, + ALL = (1 << MAX) - 1 +}; + + +// The diagnosis information of a socket. We only included a few +// members of 'struct idiagnl_msg' from libnl3-idiag, but more could +// be added later on. +class Info +{ +public: + Info(int _family, + State _state, + const Option<uint16_t>& _sourcePort, + const Option<uint16_t>& _destinationPort, + const Option<net::IP>& _sourceIP, + const Option<net::IP>& _destinationIP, + const Option<struct tcp_info>& _tcpInfo) + : family_(_family), + state_(_state), + sourcePort_(_sourcePort), + destinationPort_(_destinationPort), + sourceIP_(_sourceIP), + destinationIP_(_destinationIP), + tcpInfo_(_tcpInfo) {} + + int family() const { return family_; } + State state() const { return state_; } + const Option<uint16_t>& sourcePort() const { return sourcePort_; } + const Option<uint16_t>& destinationPort() const { return destinationPort_; } + const Option<net::IP>& sourceIP() const { return sourceIP_; } + const Option<net::IP>& destinationIP() const { return destinationIP_; } + const Option<struct tcp_info>& tcpInfo() const { return tcpInfo_; } + +private: + int family_; + State state_; + + // sourcePort, destinationPort, sourceIP and destinationIP should + // all be present because this version of kernel API that libnl3 + // uses can only return TCP sockets. We leave them as optional here + // because future support of other families could leave them as + // empty values. + Option<uint16_t> sourcePort_; + Option<uint16_t> destinationPort_; + Option<net::IP> sourceIP_; + Option<net::IP> destinationIP_; + + // tcp_info is included in the kernel header files so we expose it + // directly. + Option<struct tcp_info> tcpInfo_; +}; + + +// Return a list of socket information that matches the given protocol +// family and socket state. +// NOTE: 'family' is actually igored here because the older kernel +// idiag API libnl3 uses only supports TCP and ingores this value. We +// keep it here to follow libnl3-idiag's suit. +Try<std::vector<Info> > infos(int familiy, State states); + +} // namespace socket { + +} // namespace diagnosis { +} // namespace routing { + +#endif // __LINUX_ROUTING_DIAGNOSIS_DIAGNOSIS_HPP__ http://git-wip-us.apache.org/repos/asf/mesos/blob/5d46ce9b/src/linux/routing/internal.hpp ---------------------------------------------------------------------- diff --git a/src/linux/routing/internal.hpp b/src/linux/routing/internal.hpp index dca0dc5..87a539b 100644 --- a/src/linux/routing/internal.hpp +++ b/src/linux/routing/internal.hpp @@ -24,6 +24,8 @@ #include <netlink/netlink.h> #include <netlink/socket.h> +#include <netlink/idiag/msg.h> + #include <netlink/route/classifier.h> #include <netlink/route/link.h> #include <netlink/route/qdisc.h> @@ -44,6 +46,7 @@ inline void cleanup(struct nl_sock* sock) { nl_socket_free(sock); } inline void cleanup(struct rtnl_cls* cls) { rtnl_cls_put(cls); } inline void cleanup(struct rtnl_link* link) { rtnl_link_put(link); } inline void cleanup(struct rtnl_qdisc* qdisc) { rtnl_qdisc_put(qdisc); } +inline void cleanup(struct idiagnl_msg* msg) { idiagnl_msg_put(msg); } // A helper class for managing netlink objects (e.g., rtnl_link, @@ -81,8 +84,11 @@ private: // Returns a netlink socket for communicating with the kernel. This -// socket is needed for most of the operations. -inline Try<Netlink<struct nl_sock> > socket() +// socket is needed for most of the operations. The default protocol +// of the netlink socket is NETLINK_ROUTE, but you can optionally +// provide a different one. +// TODO(chzhcn): Consider renaming 'routing' to 'netlink'. +inline Try<Netlink<struct nl_sock> > socket(int protocol = NETLINK_ROUTE) { Try<Nothing> checking = check(); if (checking.isError()) { @@ -96,10 +102,10 @@ inline Try<Netlink<struct nl_sock> > socket() Netlink<struct nl_sock> sock(s); - int err = nl_connect(sock.get(), NETLINK_ROUTE); + int err = nl_connect(sock.get(), protocol); if (err != 0) { return Error( - "Failed to connect to routing netlink protocol: " + + "Failed to connect to netlink protocol: " + std::string(nl_geterror(err))); } http://git-wip-us.apache.org/repos/asf/mesos/blob/5d46ce9b/src/tests/routing_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/routing_tests.cpp b/src/tests/routing_tests.cpp index 10730ad..35bdf8f 100644 --- a/src/tests/routing_tests.cpp +++ b/src/tests/routing_tests.cpp @@ -38,6 +38,8 @@ #include "linux/routing/route.hpp" #include "linux/routing/utils.hpp" +#include "linux/routing/diagnosis/diagnosis.hpp" + #include "linux/routing/filter/arp.hpp" #include "linux/routing/filter/icmp.hpp" #include "linux/routing/filter/ip.hpp" @@ -228,6 +230,22 @@ TEST_F(RoutingTest, Lo) } +TEST_F(RoutingTest, INETSockets) +{ + Try<vector<diagnosis::socket::Info> > infos = + diagnosis::socket::infos(AF_INET, diagnosis::socket::State::ALL); + + EXPECT_SOME(infos); + + foreach (const diagnosis::socket::Info& info, infos.get()) { + // Both source and destination IPs should be present since + // 'AF_INET' is asked for. + EXPECT_SOME(info.sourceIP()); + EXPECT_SOME(info.destinationIP()); + } +} + + TEST_F(RoutingVethTest, ROOT_LinkCreate) { ASSERT_SOME(link::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
