tools/xdpdump/xdpdump_tool.cpp (114 lines of code) (raw):
/* 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 <folly/io/async/EventBaseManager.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <cstring>
#include <iostream>
#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> pcapWriter;
if (!FLAGS_pcap_path.empty()) {
auto fileWriter = std::make_shared<katran::FileWriter>(FLAGS_pcap_path);
pcapWriter = std::make_shared<PcapWriter>(
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;
}