diff options
-rw-r--r-- | netsniff-ng.c | 54 | ||||
-rw-r--r-- | ring_rx.c | 19 | ||||
-rw-r--r-- | ring_rx.h | 36 |
3 files changed, 102 insertions, 7 deletions
diff --git a/netsniff-ng.c b/netsniff-ng.c index dfb99bb..2eafe31 100644 --- a/netsniff-ng.c +++ b/netsniff-ng.c @@ -58,14 +58,18 @@ struct ctx { unsigned long kpull, dump_interval, tx_bytes, tx_packets; size_t reserve_size; bool randomize, promiscuous, enforce, jumbo, dump_bpf, hwtimestamp, verbose; - enum pcap_ops_groups pcap; enum dump_mode dump_mode; - uid_t uid; gid_t gid; uint32_t link_type, magic; + enum pcap_ops_groups pcap; + enum dump_mode dump_mode; + uid_t uid; + gid_t gid; + uint32_t link_type, magic; + uint32_t fanout_group, fanout_type; }; static volatile sig_atomic_t sigint = 0; static volatile bool next_dump = false; -static const char *short_options = "d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBU"; +static const char *short_options = "d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBUC:K:L:"; static const struct option long_options[] = { {"dev", required_argument, NULL, 'd'}, {"in", required_argument, NULL, 'i'}, @@ -81,6 +85,9 @@ static const struct option long_options[] = { {"user", required_argument, NULL, 'u'}, {"group", required_argument, NULL, 'g'}, {"magic", required_argument, NULL, 'T'}, + {"fanout-group", required_argument, NULL, 'C'}, + {"fanout-type", required_argument, NULL, 'K'}, + {"fanout-opts", required_argument, NULL, 'L'}, {"rand", no_argument, NULL, 'r'}, {"rfraw", no_argument, NULL, 'R'}, {"mmap", no_argument, NULL, 'm'}, @@ -377,7 +384,8 @@ static void receive_to_xmit(struct ctx *ctx) bpf_dump_all(&bpf_ops); bpf_attach_to_sock(rx_sock, &bpf_ops); - ring_rx_setup(&rx_ring, rx_sock, size_in, ifindex_in, &rx_poll, false, ctx->jumbo, ctx->verbose); + ring_rx_setup(&rx_ring, rx_sock, size_in, ifindex_in, &rx_poll, false, ctx->jumbo, + ctx->verbose, ctx->fanout_group, ctx->fanout_type); ring_tx_setup(&tx_ring, tx_sock, size_out, ifindex_out, ctx->jumbo, ctx->verbose); dissector_init_all(ctx->print_mode); @@ -925,7 +933,8 @@ static void recv_only_or_dump(struct ctx *ctx) printf("HW timestamping enabled\n"); } - ring_rx_setup(&rx_ring, sock, size, ifindex, &rx_poll, is_defined(HAVE_TPACKET3), true, ctx->verbose); + ring_rx_setup(&rx_ring, sock, size, ifindex, &rx_poll, is_defined(HAVE_TPACKET3), true, + ctx->verbose, ctx->fanout_group, ctx->fanout_type); dissector_init_all(ctx->print_mode); @@ -1073,12 +1082,15 @@ next: static void init_ctx(struct ctx *ctx) { memset(ctx, 0, sizeof(*ctx)); + ctx->uid = getuid(); ctx->uid = getgid(); ctx->cpu = -1; ctx->packet_type = -1; + ctx->fanout_type = PACKET_FANOUT_ROLLOVER; + ctx->magic = ORIGINAL_TCPDUMP_MAGIC; ctx->print_mode = PRINT_NORM; ctx->pcap = PCAP_OPS_SG; @@ -1108,6 +1120,9 @@ static void __noreturn help(void) "Options:\n" " -i|-d|--dev|--in <dev|pcap|-> Input source as netdev, pcap or pcap stdin\n" " -o|--out <dev|pcap|dir|cfg|-> Output sink as netdev, pcap, directory, trafgen, or stdout\n" + " -C|--fanout-group <id> Join packet fanout group\n" + " -K|--fanout-type <type> Apply fanout discipline: hash|lb|cpu|rnd|roll|qm\n" + " -L|--fanout-opts <opts> Additional fanout options: defrag|roll\n" " -f|--filter <bpf-file|expr> Use BPF filter file from bpfc or tcpdump-like expression\n" " -t|--type <type> Filter for: host|broadcast|multicast|others|outgoing\n" " -F|--interval <size|time> Dump interval if -o is a dir: <num>KiB/MiB/GiB/s/sec/min/hrs\n" @@ -1223,6 +1238,35 @@ int main(int argc, char **argv) ctx.gid = strtoul(optarg, NULL, 0); ctx.enforce = true; break; + case 'C': + ctx.fanout_group = strtoul(optarg, NULL, 0); + if (ctx.fanout_group == 0) + panic("Non-zero fanout group id required!\n"); + break; + case 'K': + if (!strncmp(optarg, "hash", strlen("hash"))) + ctx.fanout_type = PACKET_FANOUT_HASH; + else if (!strncmp(optarg, "lb", strlen("lb"))) + ctx.fanout_type = PACKET_FANOUT_LB; + else if (!strncmp(optarg, "cpu", strlen("cpu"))) + ctx.fanout_type = PACKET_FANOUT_CPU; + else if (!strncmp(optarg, "rnd", strlen("rnd"))) + ctx.fanout_type = PACKET_FANOUT_RND; + else if (!strncmp(optarg, "roll", strlen("roll"))) + ctx.fanout_type = PACKET_FANOUT_ROLLOVER; + else if (!strncmp(optarg, "qm", strlen("qm"))) + ctx.fanout_type = PACKET_FANOUT_QM; + else + panic("Unkown fanout type!\n"); + break; + case 'L': + if (!strncmp(optarg, "defrag", strlen("defrag"))) + ctx.fanout_type |= PACKET_FANOUT_FLAG_DEFRAG; + else if (!strncmp(optarg, "roll", strlen("roll"))) + ctx.fanout_type |= PACKET_FANOUT_FLAG_ROLLOVER; + else + panic("Unkown fanout option!\n"); + break; case 't': if (!strncmp(optarg, "host", strlen("host"))) ctx.packet_type = PACKET_HOST; @@ -209,9 +209,25 @@ static void alloc_rx_ring_frames(int sock, struct ring *ring) rx_ring_get_size(ring, v3)); } +void join_fanout_group(int sock, uint32_t fanout_group, uint32_t fanout_type) +{ + uint32_t fanout_opt = 0; + int ret; + + if (fanout_group == 0) + return; + + fanout_opt = (fanout_group & 0xffff) | (fanout_type << 16); + + ret = setsockopt(sock, SOL_PACKET, PACKET_FANOUT, &fanout_opt, + sizeof(fanout_opt)); + if (ret < 0) + panic("Cannot set fanout ring mode!\n"); +} + void ring_rx_setup(struct ring *ring, int sock, size_t size, int ifindex, struct pollfd *poll, bool v3, bool jumbo_support, - bool verbose) + bool verbose, uint32_t fanout_group, uint32_t fanout_type) { fmemset(ring, 0, sizeof(*ring)); setup_rx_ring_layout(sock, ring, size, jumbo_support, v3); @@ -219,6 +235,7 @@ void ring_rx_setup(struct ring *ring, int sock, size_t size, int ifindex, mmap_ring_generic(sock, ring); alloc_rx_ring_frames(sock, ring); bind_ring_generic(sock, ring, ifindex, false); + join_fanout_group(sock, fanout_group, fanout_type); prepare_polling(sock, poll); } @@ -13,7 +13,7 @@ extern void ring_rx_setup(struct ring *ring, int sock, size_t size, int ifindex, struct pollfd *poll, bool v3, bool jumbo_support, - bool verbose); + bool verbose, uint32_t fanout_group, uint32_t fanout_type); extern void destroy_rx_ring(int sock, struct ring *ring); extern void sock_rx_net_stats(int sock, unsigned long seen); @@ -39,4 +39,38 @@ static inline void kernel_may_pull_from_rx_block(struct block_desc *pbd) } #endif /* HAVE_TPACKET3 */ +/* Fanout types. */ + +#ifndef PACKET_FANOUT_HASH +# define PACKET_FANOUT_HASH 0 +#endif + +#ifndef PACKET_FANOUT_LB +# define PACKET_FANOUT_LB 1 +#endif + +#ifndef PACKET_FANOUT_CPU +# define PACKET_FANOUT_CPU 2 +#endif + +#ifndef PACKET_FANOUT_ROLLOVER +# define PACKET_FANOUT_ROLLOVER 3 +#endif + +#ifndef PACKET_FANOUT_RND +# define PACKET_FANOUT_RND 4 +#endif + +#ifndef PACKET_FANOUT_QM +# define PACKET_FANOUT_QM 5 +#endif + +#ifndef PACKET_FANOUT_FLAG_ROLLOVER +# define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 +#endif + +#ifndef PACKET_FANOUT_FLAG_DEFRAG +# define PACKET_FANOUT_FLAG_DEFRAG 0x8000 +#endif + #endif /* RX_RING_H */ |