Move NetlinkListener relevant files to frameworks/libs/net
NetlinkListener is used by Netd, so move it to frameworks/libs/net and then it can be used by platform code and mainline module. Bug: 209935649 Test: m; flash; boot Change-Id: I4cf0e64eee1dda1e452d76af77642416c9729d42
This commit is contained in:
parent
9f1fcb61d3
commit
b48a1205be
3 changed files with 258 additions and 0 deletions
|
|
@ -11,6 +11,7 @@ cc_library {
|
|||
"Log.cpp",
|
||||
"Netfilter.cpp",
|
||||
"Netlink.cpp",
|
||||
"NetlinkListener.cpp",
|
||||
"Slice.cpp",
|
||||
"Socket.cpp",
|
||||
"SocketOption.cpp",
|
||||
|
|
|
|||
152
staticlibs/netd/libnetdutils/NetlinkListener.cpp
Normal file
152
staticlibs/netd/libnetdutils/NetlinkListener.cpp
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "NetlinkListener"
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
|
||||
#include <log/log.h>
|
||||
#include <netdutils/Misc.h>
|
||||
#include <netdutils/NetlinkListener.h>
|
||||
#include <netdutils/Syscalls.h>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
using netdutils::Fd;
|
||||
using netdutils::Slice;
|
||||
using netdutils::Status;
|
||||
using netdutils::UniqueFd;
|
||||
using netdutils::findWithDefault;
|
||||
using netdutils::forEachNetlinkMessage;
|
||||
using netdutils::makeSlice;
|
||||
using netdutils::sSyscalls;
|
||||
using netdutils::status::ok;
|
||||
using netdutils::statusFromErrno;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kNetlinkMsgErrorType = (NFNL_SUBSYS_NONE << 8) | NLMSG_ERROR;
|
||||
|
||||
constexpr sockaddr_nl kKernelAddr = {
|
||||
.nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = 0,
|
||||
};
|
||||
|
||||
const NetlinkListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, const Slice) {
|
||||
std::stringstream ss;
|
||||
ss << nlmsg;
|
||||
ALOGE("unhandled netlink message: %s", ss.str().c_str());
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock, const std::string& name)
|
||||
: mEvent(std::move(event)), mSock(std::move(sock)), mThreadName(name) {
|
||||
const auto rxErrorHandler = [](const nlmsghdr& nlmsg, const Slice msg) {
|
||||
std::stringstream ss;
|
||||
ss << nlmsg << " " << msg << " " << netdutils::toHex(msg, 32);
|
||||
ALOGE("unhandled netlink message: %s", ss.str().c_str());
|
||||
};
|
||||
expectOk(NetlinkListener::subscribe(kNetlinkMsgErrorType, rxErrorHandler));
|
||||
|
||||
mErrorHandler = [& name = mThreadName](const int fd, const int err) {
|
||||
ALOGE("Error on NetlinkListener(%s) fd=%d: %s", name.c_str(), fd, strerror(err));
|
||||
};
|
||||
|
||||
// Start the thread
|
||||
mWorker = std::thread([this]() { run().ignoreError(); });
|
||||
}
|
||||
|
||||
NetlinkListener::~NetlinkListener() {
|
||||
const auto& sys = sSyscalls.get();
|
||||
const uint64_t data = 1;
|
||||
// eventfd should never enter an error state unexpectedly
|
||||
expectOk(sys.write(mEvent, makeSlice(data)).status());
|
||||
mWorker.join();
|
||||
}
|
||||
|
||||
Status NetlinkListener::send(const Slice msg) {
|
||||
const auto& sys = sSyscalls.get();
|
||||
ASSIGN_OR_RETURN(auto sent, sys.sendto(mSock, msg, 0, kKernelAddr));
|
||||
if (sent != msg.size()) {
|
||||
return statusFromErrno(EMSGSIZE, "unexpect message size");
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
Status NetlinkListener::subscribe(uint16_t type, const DispatchFn& fn) {
|
||||
std::lock_guard guard(mMutex);
|
||||
mDispatchMap[type] = fn;
|
||||
return ok;
|
||||
}
|
||||
|
||||
Status NetlinkListener::unsubscribe(uint16_t type) {
|
||||
std::lock_guard guard(mMutex);
|
||||
mDispatchMap.erase(type);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void NetlinkListener::registerSkErrorHandler(const SkErrorHandler& handler) {
|
||||
mErrorHandler = handler;
|
||||
}
|
||||
|
||||
Status NetlinkListener::run() {
|
||||
std::vector<char> rxbuf(4096);
|
||||
|
||||
const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice& buf) {
|
||||
std::lock_guard guard(mMutex);
|
||||
const auto& fn = findWithDefault(mDispatchMap, nlmsg.nlmsg_type, kDefaultDispatchFn);
|
||||
fn(nlmsg, buf);
|
||||
};
|
||||
|
||||
if (mThreadName.length() > 0) {
|
||||
int ret = pthread_setname_np(pthread_self(), mThreadName.c_str());
|
||||
if (ret) {
|
||||
ALOGE("thread name set failed, name: %s, ret: %s", mThreadName.c_str(), strerror(ret));
|
||||
}
|
||||
}
|
||||
const auto& sys = sSyscalls.get();
|
||||
const std::array<Fd, 2> fds{{{mEvent}, {mSock}}};
|
||||
const int events = POLLIN;
|
||||
const double timeout = 3600;
|
||||
while (true) {
|
||||
ASSIGN_OR_RETURN(auto revents, sys.ppoll(fds, events, timeout));
|
||||
// After mEvent becomes readable, we should stop servicing mSock and return
|
||||
if (revents[0] & POLLIN) {
|
||||
break;
|
||||
}
|
||||
if (revents[1] & (POLLIN|POLLERR)) {
|
||||
auto rx = sys.recvfrom(mSock, makeSlice(rxbuf), 0);
|
||||
int err = rx.status().code();
|
||||
if (err) {
|
||||
// Ignore errors. The only error we expect to see here is ENOBUFS, and there's
|
||||
// nothing we can do about that. The recvfrom above will already have cleared the
|
||||
// error indication and ensured we won't get EPOLLERR again.
|
||||
// TODO: Consider using NETLINK_NO_ENOBUFS.
|
||||
mErrorHandler(((Fd) mSock).get(), err);
|
||||
continue;
|
||||
}
|
||||
forEachNetlinkMessage(rx.value(), rxHandler);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
105
staticlibs/netd/libnetdutils/include/netdutils/NetlinkListener.h
Normal file
105
staticlibs/netd/libnetdutils/include/netdutils/NetlinkListener.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed 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 NETLINK_LISTENER_H
|
||||
#define NETLINK_LISTENER_H
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <netdutils/Netlink.h>
|
||||
#include <netdutils/Slice.h>
|
||||
#include <netdutils/Status.h>
|
||||
#include <netdutils/UniqueFd.h>
|
||||
|
||||
namespace android {
|
||||
namespace netdutils {
|
||||
|
||||
class NetlinkListenerInterface {
|
||||
public:
|
||||
using DispatchFn = std::function<void(const nlmsghdr& nlmsg, const netdutils::Slice msg)>;
|
||||
|
||||
using SkErrorHandler = std::function<void(const int fd, const int err)>;
|
||||
|
||||
virtual ~NetlinkListenerInterface() = default;
|
||||
|
||||
// Send message to the kernel using the underlying netlink socket
|
||||
virtual netdutils::Status send(const netdutils::Slice msg) = 0;
|
||||
|
||||
// Deliver future messages with nlmsghdr.nlmsg_type == type to fn.
|
||||
//
|
||||
// Threadsafe.
|
||||
// All dispatch functions invoked on a single service thread.
|
||||
// subscribe() and join() must not be called from the stack of fn().
|
||||
virtual netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) = 0;
|
||||
|
||||
// Halt delivery of future messages with nlmsghdr.nlmsg_type == type.
|
||||
// Threadsafe.
|
||||
virtual netdutils::Status unsubscribe(uint16_t type) = 0;
|
||||
|
||||
virtual void registerSkErrorHandler(const SkErrorHandler& handler) = 0;
|
||||
};
|
||||
|
||||
// NetlinkListener manages a netlink socket and associated blocking
|
||||
// service thread.
|
||||
//
|
||||
// This class is written in a generic way to allow multiple different
|
||||
// netlink subsystems to share this common infrastructure. If multiple
|
||||
// subsystems share the same message delivery requirements (drops ok,
|
||||
// no drops) they may share a single listener by calling subscribe()
|
||||
// with multiple types.
|
||||
//
|
||||
// This class is suitable for moderate performance message
|
||||
// processing. In particular it avoids extra copies of received
|
||||
// message data and allows client code to control which message
|
||||
// attributes are processed.
|
||||
//
|
||||
// Note that NetlinkListener is capable of processing multiple batched
|
||||
// netlink messages in a single system call. This is useful to
|
||||
// netfilter extensions that allow batching of events like NFLOG.
|
||||
class NetlinkListener : public NetlinkListenerInterface {
|
||||
public:
|
||||
NetlinkListener(netdutils::UniqueFd event, netdutils::UniqueFd sock, const std::string& name);
|
||||
|
||||
~NetlinkListener() override;
|
||||
|
||||
netdutils::Status send(const netdutils::Slice msg) override;
|
||||
|
||||
netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) override EXCLUDES(mMutex);
|
||||
|
||||
netdutils::Status unsubscribe(uint16_t type) override EXCLUDES(mMutex);
|
||||
|
||||
void registerSkErrorHandler(const SkErrorHandler& handler) override;
|
||||
|
||||
private:
|
||||
netdutils::Status run();
|
||||
|
||||
const netdutils::UniqueFd mEvent;
|
||||
const netdutils::UniqueFd mSock;
|
||||
const std::string mThreadName;
|
||||
std::mutex mMutex;
|
||||
std::map<uint16_t, DispatchFn> mDispatchMap GUARDED_BY(mMutex);
|
||||
std::thread mWorker;
|
||||
SkErrorHandler mErrorHandler;
|
||||
};
|
||||
|
||||
} // namespace netdutils
|
||||
} // namespace android
|
||||
|
||||
#endif /* NETLINK_LISTENER_H */
|
||||
Loading…
Reference in a new issue