diff --git a/tools/xdpdump/XdpDump.cpp b/tools/xdpdump/XdpDump.cpp deleted file mode 100644 index bf697aebe..000000000 --- a/tools/xdpdump/XdpDump.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "XdpDump.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "katran/lib/PcapWriter.h" -#include "tools/xdpdump/XdpDumpKern.h" - -namespace xdpdump { - -namespace { - -const std::string kBpfFunc = "xdpdump"; -const std::string kPcapFunc = "process"; -const std::string kRootJmpArray = "jmp"; -const std::string kPerfEventMap = "perf_event_map"; -const std::string kXdpMode = "xdp"; -constexpr int kBpfLogBufSize = 1024 * 1024 * 1; -constexpr int kIoPoolSize = 1; -int kMapPos = 0; -constexpr unsigned kNoFlags = 0; -constexpr uint32_t kNoSample = 1; -constexpr uint32_t kQueueCapacity = 2048; - -uint64_t getPossibleCpus() { - static const char* fcpu = "/sys/devices/system/cpu/possible"; - unsigned int start, end, possible_cpus = 0; - char buff[128]; - FILE* fp; - - fp = fopen(fcpu, "r"); - if (!fp) { - printf("Failed to open %s: '%s'!\n", fcpu, strerror(errno)); - exit(1); - } - - while (fgets(buff, sizeof(buff), fp)) { - if (sscanf(buff, "%u-%u", &start, &end) == 2) { - possible_cpus = start == 0 ? end + 1 : 0; - break; - } - } - - fclose(fp); - if (!possible_cpus) { - printf("Failed to retrieve # possible CPUs!\n"); - exit(1); - } - - return possible_cpus; -} - -} // namespace - -XdpDump::XdpDump( - folly::EventBase* eventBase, - XdpDumpFilter filter, - std::shared_ptr pcapWriter) - : folly::AsyncTimeout(eventBase, AsyncTimeout::InternalEnum::INTERNAL), - filter_(filter), - pcapWriter_(pcapWriter), - eventBase_(eventBase) {} - -XdpDump::~XdpDump() {} - -void XdpDump::prepareSharedMap() { - VLOG(2) << "preparing shared env: map path " << filter_.map_path - << " map pos: " << kMapPos; - - auto ts = ebpf::createSharedTableStorage(); - ts->Delete({kRootJmpArray}); - - ebpf::TableDesc desc; - desc.type = BPF_MAP_TYPE_PROG_ARRAY; - desc.name = kRootJmpArray; - desc.fd = ebpf::FileDesc(::dup(jmpFd_)); - ts->Insert({kRootJmpArray}, std::move(desc)); -} - -void XdpDump::compile() { - VLOG(2) << "compiling bpf prog"; - std::vector cflags; - for (const auto& flag : cflags_) { - LOG(INFO) << "adding compile flag: " << flag; - cflags.push_back(flag.c_str()); - } - try { - funcName_ = kBpfFunc; - VLOG(2) << "compiling xdpdump from string"; - bpf_ = std::make_unique(kNoFlags); - bpf_->load_string(kXdpDumpProg, cflags.data(), cflags.size()); - } catch (const std::runtime_error& e) { - LOG(ERROR) << "Error while load xdpdump prog"; - throw e; - } -} - -void XdpDump::prepareCflags() { - if (filter_.ipv6) { - if ((filter_.flags & kSrcSet) > 0) { - cflags_.push_back(fmt::format("-DSRCV6_0={}", filter_.srcv6[0])); - cflags_.push_back(fmt::format("-DSRCV6_1={}", filter_.srcv6[1])); - cflags_.push_back(fmt::format("-DSRCV6_2={}", filter_.srcv6[2])); - cflags_.push_back(fmt::format("-DSRCV6_3={}", filter_.srcv6[3])); - } - if ((filter_.flags & kDstSet) > 0) { - cflags_.push_back(fmt::format("-DDSTV6_0={}", filter_.dstv6[0])); - cflags_.push_back(fmt::format("-DDSTV6_1={}", filter_.dstv6[1])); - cflags_.push_back(fmt::format("-DDSTV6_2={}", filter_.dstv6[2])); - cflags_.push_back(fmt::format("-DDSTV6_3={}", filter_.dstv6[3])); - } - } else { - if ((filter_.flags & kSrcSet) > 0) { - cflags_.push_back(fmt::format("-DSRCV4={}", filter_.src)); - } - if ((filter_.flags & kDstSet) > 0) { - cflags_.push_back(fmt::format("-DDSTV4={}", filter_.dst)); - } - } - if ((filter_.flags & kSportSet) > 0) { - cflags_.push_back(fmt::format("-DSPORT={}", htons(filter_.sport))); - } - if ((filter_.flags & kDportSet) > 0) { - cflags_.push_back(fmt::format("-DDPORT={}", htons(filter_.dport))); - } - if ((filter_.flags & kProtoSet) > 0) { - cflags_.push_back(fmt::format("-DPROTO={}", filter_.proto)); - } - if (filter_.offset_len > 0) { - cflags_.push_back(fmt::format("-DOFFSET={}", filter_.offset)); - cflags_.push_back(fmt::format("-DO_LEN={}", filter_.offset_len)); - cflags_.push_back(fmt::format("-DO_PATTERN={}", filter_.pattern)); - } - if (filter_.count > 0) { - // not yet used - cflags_.push_back(fmt::format("-DCOUNT={}", filter_.count)); - } - if (filter_.cpu >= 0) { - cflags_.push_back(fmt::format("-DCPU_NUMBER={}", filter_.cpu)); - } -} - -void XdpDump::load() { - perfEventMapFd_ = bpf_->table_fd(kPerfEventMap); - if (perfEventMapFd_ < 0) { - throw std::runtime_error("cant get fd for perf map"); - } - auto fnStart = bpf_->function_start(funcName_); - if (!fnStart) { - throw std::runtime_error( - "cant find function w/ name " + folly::to(funcName_)); - } - - auto fnSize = bpf_->function_size(funcName_); - auto bpfLogBuf = std::make_unique(kBpfLogBufSize); - progFd_ = bcc_prog_load( - BPF_PROG_TYPE_XDP, - funcName_.c_str(), - reinterpret_cast(fnStart), - fnSize, - bpf_->license(), - bpf_->kern_version(), - 0 /* log_level */, - bpfLogBuf.get(), - kBpfLogBufSize); - if (progFd_ < 0) { - VLOG(2) << "fd is negative: " << progFd_ << " errno: " << errno - << " errno str: " << folly::to(std::strerror(errno)) - << " fn size: " << fnSize; - throw std::runtime_error( - "cant load bpfprog. error:" + folly::to(bpfLogBuf.get())); - } else { - VLOG(2) << "progs fd is: " << progFd_; - } -} - -void XdpDump::attach() { - auto bpfError = bpf_update_elem(jmpFd_, &kMapPos, &progFd_, 0); - if (bpfError) { - throw std::runtime_error( - "Error while updating value in map: " + - folly::to(std::strerror(errno))); - } -} - -void XdpDump::detach() { - VLOG(2) << "detaching xdpdump from rootlet"; - auto bpfError = bpf_delete_elem(jmpFd_, &kMapPos); - if (bpfError) { - throw std::runtime_error( - "Error while deleting key from map: " + folly::errnoStr(errno)); - } -} - -void XdpDump::run() { - getJmpFd(); - prepareSharedMap(); - prepareCflags(); - compile(); - load(); - pumpEventBase(); // run evbThread_ here - tryStartPcapWriter(); // create: queue_ -> writerThread_ if pcap - startEventReaders(); - startSigHandler(); - attach(); - LOG(INFO) << "Starting xdpdump"; - sleepForever(); - LOG(INFO) << "Detaching bpf"; - detach(); - LOG(INFO) << "Finalized xdpdump"; -} - -void XdpDump::timeoutExpired() noexcept { - stop(); -} - -void XdpDump::getJmpFd() { - jmpFd_ = bpf_obj_get(filter_.map_path.c_str()); - if (jmpFd_ < 0) { - throw std::runtime_error( - "cant get fd of shared map, probably xdp is not supported"); - } -} - -void XdpDump::sleepForever() { - // Wait until XdpDump::stop won't terminate eventBase_ - writerThread_.join(); -} - -void XdpDump::pumpEventBase() { - if (!eventBase_->isRunning()) { - evbThread_ = std::thread([this]() { - this->eventBase_->loopForever(); - VLOG(3) << "End of evbThread"; - }); - } -} - -void XdpDump::tryStartPcapWriter() { - if (pcapWriter_) { - queue_ = - std::make_shared>(kQueueCapacity); - writerThread_ = std::thread([this]() { - this->eventBase_->waitUntilRunning(); - this->pcapWriter_->run(this->queue_); - this->eventBase_->terminateLoopSoon(); - this->evbThread_.join(); - VLOG(3) << "End of writerThread"; - }); - } else { - writerThread_ = std::thread([this]() { - this->evbThread_.join(); - VLOG(3) << "End of writerThread"; - }); - } -} - -void XdpDump::startEventReaders() { - uint64_t numCpu = getPossibleCpus(); - std::shared_ptr eventLogger_; - eventLogger_ = std::make_shared(filter_.mute, std::cerr); - for (int cpu = 0; cpu < numCpu; ++cpu) { - auto reader = std::make_unique(queue_, eventLogger_); - if (!reader->open(perfEventMapFd_, eventBase_, kNoSample)) { - LOG(ERROR) << "Perf event queue init failed for cpu: " << cpu; - } else { - eventReaders_.push_back(std::move(reader)); - } - } - if (eventReaders_.size() == 0) { - throw std::runtime_error("none of eventReaders were initialized"); - } -} - -void XdpDump::startSigHandler() { - sigHandler_ = std::make_unique(eventBase_, this); - sigHandler_->registerSignalHandler(SIGTERM); - sigHandler_->registerSignalHandler(SIGINT); -} - -void XdpDump::clear() { - VLOG(2) << "removing xdpdump from shared array"; - getJmpFd(); - detach(); -} - -void XdpDump::stop() { - if (queue_) { - VLOG(2) << "stoping pcap writer"; - katran::PcapMsg stopMsg(nullptr, 0, 0); - queue_->blockingWrite(std::move(stopMsg)); - } else { - eventBase_->terminateLoopSoon(); - } - - VLOG(2) << "XdpDump is stopped"; -} - -XdpDump::XdpDumpSignalHandler::XdpDumpSignalHandler( - folly::EventBase* evb, - XdpDump* parent) - : folly::AsyncSignalHandler(evb) { - parent_ = parent; -} - -void XdpDump::XdpDumpSignalHandler::signalReceived(int signum) noexcept { - LOG(INFO) << "Signal: " << signum << ", stopping xdpdump"; - parent_->stop(); -} - -} // namespace xdpdump diff --git a/tools/xdpdump/XdpDump.h b/tools/xdpdump/XdpDump.h deleted file mode 100644 index 1cd1567c3..000000000 --- a/tools/xdpdump/XdpDump.h +++ /dev/null @@ -1,238 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "katran/lib/PcapMsg.h" -#include "tools/xdpdump/XdpDumpStructs.h" -#include "tools/xdpdump/XdpEventReader.h" - -namespace folly { -class EventBase; -} - -namespace xdpdump { - -/** - * flags which show which field is set in filter struct - */ -constexpr uint8_t kSrcSet = (1 << 0); -constexpr uint8_t kDstSet = (1 << 1); -constexpr uint8_t kSportSet = (1 << 2); -constexpr uint8_t kDportSet = (1 << 3); -constexpr uint8_t kProtoSet = (1 << 4); - -/** - * Main class which implements xdpdump util - tcpdump like util to capture - * packets on "XDP level" (as xdp could either drop or tx this packets - we - * we wont be able to see em with tcpdump as this packets will never hit - * kernel's tcp/ip stack). - */ -class XdpDump : public folly::AsyncTimeout { - public: - /** - * @param EventBase* eventBase for AsyncTimeout - * @param XdpDumpFilter filter - * @param std::shared_ptr pcapWriter - * - * we pass filter object which contains all the field (such as src/dst/ - * or a line for pcap-based filter) which describes what packets we want to - * capture - */ - explicit XdpDump( - folly::EventBase* eventBase, - XdpDumpFilter filter, - std::shared_ptr pcapWriter); - - /** - * Destructor for XdpDump. - */ - ~XdpDump(); - - /** - * helper function to remove xdpdump from rootlet's root array - */ - void clear(); - - /** - * helper function which starts xdpdump - */ - void run(); - - /** - * timeout function - */ - virtual void timeoutExpired() noexcept override; - - private: - /** - * helper class which implements sighandler. this allow us to detach - * xdpdump from rootlets array when user decided to stop the program. - */ - class XdpDumpSignalHandler : public folly::AsyncSignalHandler { - public: - XdpDumpSignalHandler(folly::EventBase* evb, XdpDump* parent); - ~XdpDumpSignalHandler() override {} - - void signalReceived(int signum) noexcept override; - - private: - XdpDump* parent_; - }; - /** - * helper function which compiles bpf program. - */ - void compile(); - - /** - * helper function which loads bpf program in kernel - */ - void load(); - - /** - * helper function which prepares and passing rootlet's prog fd to bpf prog - */ - void prepareSharedMap(); - - /** - * helper function which retrievs rootlet's jump table fd from pinned map - */ - void getJmpFd(); - - /** - * helper function to pump eventBase_ - */ - void pumpEventBase(); - - /** - * helper function which start pcap writer if needed - */ - void tryStartPcapWriter(); - - /** - * helper function which start perf event reader - */ - void startEventReaders(); - - /** - * helper function which starts signal handler - */ - void startSigHandler(); - - /** - * helper function which attaches loaded bpf program to rootlet. - */ - void attach(); - - /** - * helper function which detaches xdpdump from rootlet's array - */ - void detach(); - - /** - * as we are doing all the work in separate threads we need to block our main - * one. this function is basicaly blocks main thread "waiting for evb to stop" - * (which happens only on sigint receiving) - */ - void sleepForever(); - - /** - * helper function which prepares cflags for bpf prog compilation. - * cflags are based on info which has been provided inside XdpDumpFilter - * struct - */ - void prepareCflags(); - - /** - * helper function which stop both pcapWriter (if running) - * and detach xdpdump from rootlet - */ - void stop(); - - /** - * structs which describes in what packets are we interested in - * as well as contains some metainfo (such as rootlets map location/ - * our position in it/ pcap's file location etc etc etc) - */ - XdpDumpFilter filter_; - - /** - * pcapWriter is used to store pcap-data into file or byte range. - */ - std::shared_ptr pcapWriter_{nullptr}; - - /** - * bpf provider which is used to created bpf prog. depends on configuration - * could be either Bcc or Pcap compiler - */ - std::unique_ptr bpf_; - - /** - * evbThread, which run all event readers and sighandler. - */ - std::thread evbThread_; - - int perfEventMapFd_; - /** - * bpf prog fd - */ - int progFd_; - - /** - * fd of rootlet's jump array (array of bpf progs) - */ - int jmpFd_; - - /** - * vector of eventReaders (there is one event reader per cpu core) - */ - std::vector> eventReaders_; - - /** - * vector of cflags, which are passed to bpf backedn during compilation phase - */ - std::vector cflags_; - std::unique_ptr sigHandler_; - std::thread writerThread_; - - /** - * MPMCQueue where we pass PcapMsg from perfEventReaders to PcapWriter - */ - std::shared_ptr> queue_; - - /** - * name of main bpf function - */ - std::string funcName_; - - /** - * name of main bpf function - */ - folly::EventBase* eventBase_; -}; - -} // namespace xdpdump diff --git a/tools/xdpdump/XdpDumpKern.h b/tools/xdpdump/XdpDumpKern.h deleted file mode 100644 index bcc6a6912..000000000 --- a/tools/xdpdump/XdpDumpKern.h +++ /dev/null @@ -1,274 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#pragma once -#include - -const std::string kXdpDumpProg = R"***( - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -// we dont want to do htons for each packet, so this is ETH_P_IPV6 and -// ETH_P_IP in be format -#define BE_ETH_P_IP 8 -#define BE_ETH_P_IPV6 56710 -#define MAX_LEN 128 - -#define IPV4_HDR_LEN_NO_OPT 20 -#define IPV4_PLUS_ICMP_HDR 28 -#define IPV6_PLUS_ICMP_HDR 48 - -// cleint's packet metadata -struct packet_description { - union { - __be32 src; - __be32 srcv6[4]; - }; - union { - __be32 dst; - __be32 dstv6[4]; - }; - union { - __u32 ports; - __u16 port16[2]; - }; - __u8 proto; - __u8 flags; -}; - -struct XdpDumpOutput { - union { - __u32 src; - __u32 srcv6[4]; - }; - union { - __u32 dst; - __u32 dstv6[4]; - }; - bool ipv6; - __u16 sport; - __u16 dport; - __u8 proto; - __u16 pkt_size; - __u16 data_len; -}; - - -BPF_TABLE("extern", __u32, __u32, jmp, 16); -BPF_PERF_OUTPUT(perf_event_map); - -__attribute__((__always_inline__)) -static inline __u64 calc_offset(bool is_ipv6) { - __u64 off = sizeof(struct ethhdr); - if (is_ipv6) { - off += sizeof(struct ipv6hdr); - } else { - off += sizeof(struct iphdr); - } - return off; -} - -__attribute__((__always_inline__)) -static inline bool parse_udp(void *data, void *data_end, - bool is_ipv6, - struct packet_description *pckt) { - - __u64 off = calc_offset(is_ipv6); - struct udphdr *udp; - udp = data + off; - - if ((void *)(udp + 1) > data_end) { - return false; - } - - pckt->port16[0] = udp->source; - pckt->port16[1] = udp->dest; - return true; -} - - -__attribute__((__always_inline__)) -static inline bool parse_tcp(void *data, void *data_end, - bool is_ipv6, - struct packet_description *pckt) { - - __u64 off = calc_offset(is_ipv6); - struct tcphdr *tcp; - tcp = data + off; - - if ((void *)(tcp + 1) > data_end) { - return false; - } - - pckt->port16[0] = tcp->source; - pckt->port16[1] = tcp->dest; - return true; -} - -__attribute__((__always_inline__)) -static inline void process_packet(void *data, __u64 off, void *data_end, - bool is_ipv6, struct xdp_md *xdp) { - struct iphdr *iph; - struct ipv6hdr *ip6h; - struct packet_description pckt = {}; - __u64 iph_len; - __u8 protocol; - struct XdpDumpOutput output = {}; - - #ifdef CPU_NUMBER - if (bpf_get_smp_processor_id() != CPU_NUMBER) { - return; - } - #endif - - if (is_ipv6) { - ip6h = data + off; - if ((void *)(ip6h + 1) > data_end) { - return; - } - - iph_len = sizeof(struct ipv6hdr); - protocol = ip6h->nexthdr; - pckt.proto = protocol; - off += iph_len; - memcpy(pckt.srcv6, ip6h->saddr.s6_addr32, 16); - memcpy(pckt.dstv6, ip6h->daddr.s6_addr32, 16); - } else { - iph = data + off; - if ((void *)(iph + 1) > data_end) { - return; - } - - protocol = iph->protocol; - pckt.proto = protocol; - off += IPV4_HDR_LEN_NO_OPT; - - pckt.src = iph->saddr; - pckt.dst = iph->daddr; - } - protocol = pckt.proto; - - if (protocol == IPPROTO_TCP) { - parse_tcp(data, data_end, is_ipv6, &pckt); - } else if (protocol == IPPROTO_UDP) { - parse_udp(data, data_end, is_ipv6, &pckt); - } - #ifdef SRCV6_0 - if ((pckt.srcv6[0] != SRCV6_0) || - (pckt.srcv6[1] != SRCV6_1) || - (pckt.srcv6[2] != SRCV6_2) || - (pckt.srcv6[3] != SRCV6_3)) { - return; - } - #endif - #ifdef DSTV6_0 - if ((pckt.dstv6[0] != DSTV6_0) || - (pckt.dstv6[1] != DSTV6_1) || - (pckt.dstv6[2] != DSTV6_2) || - (pckt.dstv6[3] != DSTV6_3)) { - return; - } - #endif - #ifdef SRCV4 - if(pckt.src != SRCV4) { - return; - } - #endif - #ifdef DSTV4 - if(pckt.dst != DSTV4) { - return; - } - #endif - #ifdef SPORT - if(pckt.port16[0] != SPORT) { - return; - } - #endif - #ifdef DPORT - if(pckt.port16[1] != DPORT) { - return; - } - #endif - #ifdef PROTO - if(pckt.proto != PROTO) { - return; - } - #endif - #ifdef OFFSET - if((data + sizeof(struct ethhdr) + OFFSET + sizeof(__u32)) > data_end) { - return; - } - __u32 pkt_chunk = *(__u32 *)(data + sizeof(struct ethhdr) + OFFSET); - pkt_chunk &=(0xFFFFFFFF >> ((4 - O_LEN) * 8)); - if ((pkt_chunk & O_PATTERN) != O_PATTERN) { - return; - } - #endif - - output.ipv6 = is_ipv6; - if (is_ipv6) { - memcpy(output.srcv6, pckt.srcv6, 16); - memcpy(output.dstv6, pckt.dstv6, 16); - } else { - output.src = pckt.src; - output.dst = pckt.dst; - } - output.sport = pckt.port16[0]; - output.dport = pckt.port16[1]; - output.proto = pckt.proto; - output.pkt_size = data_end - data; - __u16 data_len = output.pkt_size < MAX_LEN ? output.pkt_size : MAX_LEN; - output.data_len = data_len; - perf_event_map.perf_submit_skb(xdp, data_len, &output, sizeof(output)); - return; -} - -__attribute__((__always_inline__)) -int xdpdump(struct xdp_md *ctx) { - void *data = (void *)(long)ctx->data; - void *data_end = (void *)(long)ctx->data_end; - struct ethhdr *eth = data; - __u32 eth_proto; - __u32 nh_off; - nh_off = sizeof(struct ethhdr); - - if (!(data + nh_off > data_end)) { - eth_proto = eth->h_proto; - - if (eth_proto == BE_ETH_P_IP) { - process_packet(data, nh_off, data_end, false, ctx); - } else if (eth_proto == BE_ETH_P_IPV6) { - process_packet(data, nh_off, data_end, true, ctx); - } - } - #pragma clang loop unroll(full) - for (int i = 1; i < 16; i++) { - jmp.call((void *)ctx, i); - } - return XDP_PASS; -} - -)***"; diff --git a/tools/xdpdump/XdpDumpStructs.h b/tools/xdpdump/XdpDumpStructs.h deleted file mode 100644 index d3ace900e..000000000 --- a/tools/xdpdump/XdpDumpStructs.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#pragma once -#include - -namespace xdpdump { - -struct XdpDumpFilter { - union { - uint32_t src; - uint32_t srcv6[4]; - }; - union { - uint32_t dst; - uint32_t dstv6[4]; - }; - uint16_t sport; - uint16_t dport; - uint8_t proto; - bool ipv6; - uint16_t offset; - uint16_t offset_len; - uint32_t pattern; - std::string map_path; - uint8_t flags; - uint64_t count; - bool mute; - int32_t cpu; - int32_t pages; -}; - -extern "C" { -struct XdpDumpOutput { - union { - uint32_t src; - uint32_t srcv6[4]; - }; - union { - uint32_t dst; - uint32_t dstv6[4]; - }; - bool ipv6; - uint16_t sport; - uint16_t dport; - uint8_t proto; - uint16_t pkt_size; - uint16_t data_len; -}; -} -} // namespace xdpdump diff --git a/tools/xdpdump/XdpEventLogger.cpp b/tools/xdpdump/XdpEventLogger.cpp deleted file mode 100644 index 3c8faee90..000000000 --- a/tools/xdpdump/XdpEventLogger.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "tools/xdpdump/XdpEventLogger.h" - -#include -#include -#include - -namespace xdpdump { - -namespace { - -constexpr uint8_t kIPv6AddrSize = 16; -} - -std::string XdpEventLogger::binaryToV6String(uint8_t const* v6) { - folly::ByteRange bytes(v6, kIPv6AddrSize); - return folly::IPAddressV6::fromBinary(bytes).str(); -} - -std::string XdpEventLogger::longToV4String(uint32_t v4) { - return folly::IPAddressV4::fromLong(v4).str(); -} - -XdpEventInfo ProgLogger::handlePerfEvent(const char* data) { - auto msg = reinterpret_cast(data); - XdpEventInfo info; - info.pkt_size = msg->pkt_size; - info.data_len = msg->data_len; - info.hdr_size = sizeof(struct XdpDumpOutput); - if (!mute_) { - log(msg); - } - return info; -} - -void ProgLogger::log(const XdpDumpOutput* msg) { - if (msg->ipv6) { - out_ << "srcv6: " << binaryToV6String((uint8_t*)&msg->srcv6) - << " dstv6: " << binaryToV6String((uint8_t*)&msg->dstv6) << std::endl; - } else { - out_ << "src: " << longToV4String(msg->src) - << " dst: " << longToV4String(msg->dst) << std::endl; - } - out_ << "proto: " << (uint16_t)msg->proto << " sport: " << ntohs(msg->sport) - << " dport: " << ntohs(msg->dport) << " pkt size: " << msg->pkt_size - << " chunk size: " << msg->data_len << std::endl; -} - -} // namespace xdpdump diff --git a/tools/xdpdump/XdpEventLogger.h b/tools/xdpdump/XdpEventLogger.h deleted file mode 100644 index e040d3fd3..000000000 --- a/tools/xdpdump/XdpEventLogger.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#pragma once - -#include -#include "tools/xdpdump/XdpDumpStructs.h" - -namespace xdpdump { - -struct XdpEventInfo { - uint32_t data_len{0}; - uint32_t hdr_size{0}; - uint32_t pkt_size{0}; -}; - -class XdpEventLogger { - public: - /** - * @param bool mute set true if logger shouldn't write any data into out - * @param std::ostream& out is an ostream where logs are saved - * - * Constructor for XdpEventLogger - */ - explicit XdpEventLogger(bool mute, std::ostream& out) - : mute_(mute), out_(out) {} - - /** - * Virtual destructor - */ - virtual ~XdpEventLogger() = default; - - /** - * @param const char* data received from the XDP prog. - * - * Function that processes handleEvent, produces XdpEventInfo, and, - * if required, logs some data. - */ - virtual XdpEventInfo handlePerfEvent(const char* data) = 0; - - protected: - /* - * @param uint8_t const* v6 is an array of 16 bytes - * - * Converts bytes of IPv6 address into the std::string - */ - static std::string binaryToV6String(uint8_t const* v6); - - /* - * @param uint32_t v4 is an IPv4 address - * - * Converts IPv4 address presented by uint32 into the std::string - */ - static std::string longToV4String(uint32_t v4); - - /** - * mute_ set true if logger shouldn't write any data into out_ - */ - const bool mute_{false}; - - /** - * out_ is a stream where all information will be logged in. - */ - std::ostream& out_; -}; - -class ProgLogger : public XdpEventLogger { - public: - /** - * @param bool mute set if logger should write any data into out - * @param std::ostream& out is an ostream where logs are saved - * - * Constructor for ProgLogger - */ - ProgLogger(bool mute, std::ostream& out) : XdpEventLogger(mute, out) {} - - /** - * @param const char* data received from the XDP prog. - * - * Overrides XdpEventLogger::handlePerfEvent - */ - virtual XdpEventInfo handlePerfEvent(const char* data) override; - - private: - /** - * @param XdpDumpOutput* msg - * - * Logs prog data - */ - void log(const XdpDumpOutput* msg); -}; -} // namespace xdpdump diff --git a/tools/xdpdump/XdpEventReader.cpp b/tools/xdpdump/XdpEventReader.cpp deleted file mode 100644 index 195aed5f6..000000000 --- a/tools/xdpdump/XdpEventReader.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "tools/xdpdump/XdpEventReader.h" - -#include -#include -#include -#include - -namespace xdpdump { - -void XdpEventReader::handlePerfBufferEvent( - int /* cpu */, - const char* data, - size_t /* size */) noexcept { - auto info = eventLogger_->handlePerfEvent(data); - if (queue_ != nullptr) { - katran::PcapMsg pcap_msg( - data + info.hdr_size, info.pkt_size, info.data_len); - // best effort non blocking write. if writer thread is full we will lose - // this packet - auto res = queue_->write(std::move(pcap_msg)); - if (!res) { - // queue is full and we wasnt able to write into it. - ++queueFull_; - } - } -} - -} // namespace xdpdump diff --git a/tools/xdpdump/XdpEventReader.h b/tools/xdpdump/XdpEventReader.h deleted file mode 100644 index 01770c9f6..000000000 --- a/tools/xdpdump/XdpEventReader.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#pragma once - -#include -#include - -#include -#include -#include "katran/lib/PerfBufferEventReader.h" - -#include "katran/lib/PcapMsg.h" -#include "katran/lib/PcapWriter.h" -#include "tools/xdpdump/XdpDumpStructs.h" -#include "tools/xdpdump/XdpEventLogger.h" - -namespace xdpdump { - -class XdpEventLogger; - -/** - * Perf event reader implementation. we are reading data - * from XDP, print it to the cli, and, if configured - * sending it to pcapWriter thru MPMCQueue. - */ -class XdpEventReader : public katran::PerfBufferEventReader { - public: - /** - * @param shared_ptr> queue to pcapWriter - */ - explicit XdpEventReader( - std::shared_ptr> queue, - std::shared_ptr eventLogger) - : queue_(queue), eventLogger_(eventLogger) {} - - /** - * @param int cpu - * @param const char* data received from the XDP prog. - * @param size_t size of the data chunk - */ - void handlePerfBufferEvent(int cpu, const char* data, size_t size) noexcept - override; - - private: - /** - * queue where we write data, which will be read by PcapWriter. - * write is non-blocking. so if queue is full - we will drop the packet - */ - std::shared_ptr> queue_; - - /** - * counter of how many times non blocking write failed. - */ - uint64_t queueFull_; - - std::shared_ptr eventLogger_; -}; - -} // namespace xdpdump diff --git a/tools/xdpdump/xdpdump_tool.cpp b/tools/xdpdump/xdpdump_tool.cpp deleted file mode 100644 index 087cb418c..000000000 --- a/tools/xdpdump/xdpdump_tool.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* Copyright (C) 2018-present, Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include - -#include "katran/lib/IpHelpers.h" - -#include "katran/lib/FileWriter.h" -#include "katran/lib/PcapWriter.h" -#include "tools/xdpdump/XdpDump.h" -#include "tools/xdpdump/XdpDumpStructs.h" - -DEFINE_string(src, "", "source ip address"); -DEFINE_string(dst, "", "destination ip address"); -DEFINE_int32(sport, 0, "source port"); -DEFINE_int32(dport, 0, "destination port"); -DEFINE_int32(proto, 0, "protocol to match"); -DEFINE_int32(offset, 0, "offset for byte matching"); -DEFINE_int32(offset_len, 0, "length fot the bytematching; up to 4"); -DEFINE_int32(cpu, -1, "cpu to take dump from"); -DEFINE_int64(pattern, 0, "pattern for bytematching; up to 4bytes"); -DEFINE_string(map_path, "/sys/fs/bpf/jmp_eth0", "path to root jump array"); -DEFINE_string(pcap_path, "", "path to pcap file"); -DEFINE_int32( - packet_limit, - 0, - "max number of packets to be written in pcap file"); -DEFINE_bool(clear, false, "remove xdpdump from shared array"); -DEFINE_bool(mute, false, "switch off output of received packets"); -DEFINE_int32( - snaplen, - 0, - "max length of the packet that will be captured " - "(set 0 to capture whole packet)"); -DEFINE_int32( - bpf_mmap_pages, - 2, - "How many pages should be mmap-ed to the perf event for each CPU. " - "It must be a power of 2."); -DEFINE_int32(duration_ms, -1, "how long to take a capture"); - -using PcapWriter = katran::PcapWriter; - -int main(int argc, char** argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - google::InitGoogleLogging(argv[0]); - xdpdump::XdpDumpFilter filter = {}; - // flags to filter parsing - if (!FLAGS_src.empty()) { - filter.flags |= xdpdump::kSrcSet; - auto src_addr = katran::IpHelpers::parseAddrToBe(FLAGS_src); - if (src_addr.flags > 0) { - // ipv6 - std::memcpy(&filter.srcv6, &src_addr.v6daddr, 16); - filter.ipv6 = true; - } else { - filter.src = src_addr.daddr; - } - } - if (!FLAGS_dst.empty()) { - filter.flags |= xdpdump::kDstSet; - auto dst_addr = katran::IpHelpers::parseAddrToBe(FLAGS_dst); - if (dst_addr.flags > 0) { - // ipv6 - if (!FLAGS_src.empty() && !filter.ipv6) { - // src is specified and it's ipv4 - std::cout << "v4 src and v6 dst is not supported\n"; - return -1; - } - std::memcpy(&filter.dstv6, &dst_addr.v6daddr, 16); - filter.ipv6 = true; - } else { - if (filter.ipv6) { - // src is specified and it's ipv6 - std::cout << "v6 src and v4 dst is not supported\n"; - return -1; - } - filter.dst = dst_addr.daddr; - } - } - if (FLAGS_snaplen < 0 || FLAGS_snaplen > 0xFFFF) { - std::cout << "snaplen should be between 0 and 65535." - << " Set to 0 to capture whole packet." << std::endl; - return -1; - } - - if (FLAGS_sport != 0) { - filter.flags |= xdpdump::kSportSet; - filter.sport = (uint16_t)FLAGS_sport; - } - if (FLAGS_dport != 0) { - filter.flags |= xdpdump::kDportSet; - filter.dport = (uint16_t)FLAGS_dport; - } - if (FLAGS_proto != 0) { - filter.flags |= xdpdump::kProtoSet; - filter.proto = (uint8_t)FLAGS_proto; - } - - filter.offset = (uint16_t)FLAGS_offset; - filter.offset_len = (uint16_t)FLAGS_offset_len; - filter.pattern = (uint32_t)FLAGS_pattern; - filter.map_path = FLAGS_map_path; - filter.mute = FLAGS_mute; - filter.cpu = FLAGS_cpu; - filter.pages = FLAGS_bpf_mmap_pages; - // end of parsing - - std::shared_ptr pcapWriter; - if (!FLAGS_pcap_path.empty()) { - auto fileWriter = std::make_shared(FLAGS_pcap_path); - pcapWriter = std::make_shared( - fileWriter, FLAGS_packet_limit, FLAGS_snaplen); - } - - auto evb = folly::EventBaseManager::get()->getEventBase(); - xdpdump::XdpDump xdpdump(evb, filter, pcapWriter); - - try { - if (FLAGS_clear) { - xdpdump.clear(); - } else { - // if (FLAGS_duration_ms.count() != 0) { - // xdpdump.scheduleTimeout(FLAGS_duration_ms); - //} - xdpdump.run(); - } - } catch (const std::runtime_error& e) { - LOG(ERROR) << "XdpDump error: " << e.what(); - } - return 0; -}